Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
<PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.IO;
using System.Linq;
using Microsoft.Bot.Builder.Dialogs.Declarative.Resources;

namespace Microsoft.Bot.Builder.AI.QnA.Tests
{
public class QnAMakerRecognizerFixture : IDisposable
{
public QnAMakerRecognizerFixture()
{
var parent = Environment.CurrentDirectory;
while (!string.IsNullOrEmpty(parent))
{
if (Directory.EnumerateFiles(parent, "*proj").Any())
{
break;
}

parent = Path.GetDirectoryName(parent);
}

ResourceExplorer = new ResourceExplorer()
.AddFolder(parent, monitorChanges: false);
}

public ResourceExplorer ResourceExplorer { get; set; }

public void Dispose()
{
ResourceExplorer.Dispose();
}
}
}
115 changes: 45 additions & 70 deletions tests/Microsoft.Bot.Builder.AI.QnA.Tests/QnAMakerRecognizerTests.cs
Original file line number Diff line number Diff line change
@@ -1,58 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma warning disable SA1201 // Elements should appear in the correct order

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.AI.QnA.Recognizers;
using Microsoft.Bot.Builder.AI.QnA.Tests;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Adaptive;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Actions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Conditions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Templates;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.Actions;
using Microsoft.Bot.Builder.Dialogs.Declarative.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using RichardSzalay.MockHttp;
using Xunit;

namespace Microsoft.Bot.Builder.AI.Tests
{
[TestClass]
public class QnAMakerRecognizerTests
public class QnAMakerRecognizerTests : IClassFixture<QnAMakerRecognizerFixture>
{
private const string _knowledgeBaseId = "dummy-id";
private const string _endpointKey = "dummy-key";
private const string _hostname = "https://dummy-hostname.azurewebsites.net/qnamaker";
private const string KnowledgeBaseId = "dummy-id";
private const string EndpointKey = "dummy-key";
private const string Hostname = "https://dummy-hostname.azurewebsites.net/qnamaker";

public static ResourceExplorer ResourceExplorer { get; set; }
private readonly QnAMakerRecognizerFixture _qnaMakerRecognizerFixture;

public TestContext TestContext { get; set; }

[ClassInitialize]
public static void ClassInitialize(TestContext context)
public QnAMakerRecognizerTests(QnAMakerRecognizerFixture qnaMakerRecognizerFixture)
{
var parent = Environment.CurrentDirectory;
while (!string.IsNullOrEmpty(parent))
{
if (Directory.EnumerateFiles(parent, "*proj").Any())
{
break;
}
else
{
parent = Path.GetDirectoryName(parent);
}
}

ResourceExplorer = new ResourceExplorer()
.AddFolder(parent, monitorChanges: false);
_qnaMakerRecognizerFixture = qnaMakerRecognizerFixture;
}

public AdaptiveDialog QnAMakerRecognizer_DialogBase()
Expand All @@ -74,28 +54,28 @@ public AdaptiveDialog QnAMakerRecognizer_DialogBase()
return CreateQnAMakerActionDialog(mockHttp);
}

[TestMethod]
[Fact]
public async Task QnAMakerRecognizer_WithTopNAnswer()
{
var rootDialog = QnAMakerRecognizer_DialogBase();

var response = JsonConvert.DeserializeObject<QueryResults>(File.ReadAllText(GetFilePath("QnaMaker_TopNAnswer.json")));

await CreateFlow(rootDialog)
await CreateFlow(rootDialog, nameof(QnAMakerRecognizer_WithTopNAnswer))
.Send("QnaMaker_TopNAnswer")
.AssertReply(response.Answers[0].Answer)
.AssertReply("done")
.StartTestAsync();
}

[TestMethod]
[Fact]
public async Task QnAMakerRecognizer_WithAnswer()
{
var rootDialog = QnAMakerRecognizer_DialogBase();

var response = JsonConvert.DeserializeObject<QueryResults>(File.ReadAllText(GetFilePath("QnaMaker_ReturnsAnswer.json")));

await CreateFlow(rootDialog)
await CreateFlow(rootDialog, nameof(QnAMakerRecognizer_WithAnswer))
.Send("QnaMaker_ReturnsAnswer")
.AssertReply(response.Answers[0].Answer)
.AssertReply("done")
Expand All @@ -104,119 +84,114 @@ await CreateFlow(rootDialog)
.StartTestAsync();
}

[TestMethod]
[Fact]
public async Task QnAMakerRecognizer_WithNoAnswer()
{
var rootDialog = QnAMakerRecognizer_DialogBase();
var response = JsonConvert.DeserializeObject<QueryResults>(File.ReadAllText(GetFilePath("QnaMaker_ReturnsAnswer_WhenNoAnswerFoundInKb.json")));

await CreateFlow(rootDialog)
await CreateFlow(rootDialog, nameof(QnAMakerRecognizer_WithNoAnswer))
.Send("QnaMaker_ReturnsNoAnswer")
.AssertReply("Wha?")
.StartTestAsync();
}

[TestMethod]
[Fact]
public async Task QnAMakerRecognizer_WithIntent()
{
var rootDialog = QnAMakerRecognizer_DialogBase();

await CreateFlow(rootDialog)
await CreateFlow(rootDialog, nameof(QnAMakerRecognizer_WithIntent))
.Send("QnaMaker_ReturnsAnswerWithIntent")
.AssertReply("DeferToRecognizer_xxx")
.StartTestAsync();
}

private TestFlow CreateFlow(Dialog rootDialog)
private TestFlow CreateFlow(Dialog rootDialog, string testName)
{
var storage = new MemoryStorage();
var userState = new UserState(storage);
var conversationState = new ConversationState(storage);

var adapter = new TestAdapter(TestAdapter.CreateConversation(TestContext.TestName));
var adapter = new TestAdapter(TestAdapter.CreateConversation(testName));
adapter
.UseStorage(storage)
.UseBotState(userState, conversationState)
.Use(new TranscriptLoggerMiddleware(new TraceTranscriptLogger(traceActivity: false)));
.Use(new TranscriptLoggerMiddleware(new TraceTranscriptLogger(false)));

DialogManager dm = new DialogManager(rootDialog)
.UseResourceExplorer(ResourceExplorer)
var dm = new DialogManager(rootDialog)
.UseResourceExplorer(_qnaMakerRecognizerFixture.ResourceExplorer)
.UseLanguageGeneration();

return new TestFlow(adapter, async (turnContext, cancellationToken) =>
{
await dm.OnTurnAsync(turnContext, cancellationToken: cancellationToken).ConfigureAwait(false);
await dm.OnTurnAsync(turnContext, cancellationToken).ConfigureAwait(false);
});
}

private AdaptiveDialog CreateQnAMakerActionDialog(MockHttpMessageHandler mockHttp)
{
var client = new HttpClient(mockHttp);

var host = "https://dummy-hostname.azurewebsites.net/qnamaker";
var knowlegeBaseId = "dummy-id";
var endpointKey = "dummy-key";

var rootDialog = new AdaptiveDialog("outer")
{
AutoEndDialog = false,
Recognizer = new QnAMakerRecognizer()
Recognizer = new QnAMakerRecognizer
{
KnowledgeBaseId = knowlegeBaseId,
HostName = host,
EndpointKey = endpointKey,
KnowledgeBaseId = KnowledgeBaseId,
HostName = Hostname,
EndpointKey = EndpointKey,
HttpClient = client
},
Triggers = new List<OnCondition>()
Triggers = new List<OnCondition>
{
new OnQnAMatch()
new OnQnAMatch
{
Actions = new List<Dialog>()
Actions = new List<Dialog>
{
new SendActivity()
new SendActivity
{
Activity = new ActivityTemplate("${@answer}")
},
new AssertCondition()
new AssertCondition
{
Condition = "count(turn.recognized.entities.answer) == 1",
Description = "If there is a match there should only be 1 answer"
},
new AssertCondition()
new AssertCondition
{
Condition = "turn.recognized.entities.$instance.answer[0].startIndex == 0",
Description = "startIndex should be 0",
},
new AssertCondition()
new AssertCondition
{
Condition = "turn.recognized.entities.$instance.answer[0].endIndex != null",
Description = "endIndex should not be null",
},
new AssertCondition()
new AssertCondition
{
Condition = "turn.recognized.answers[0].answer != null",
Description = "There should be answers object"
},
new SendActivity()
new SendActivity
{
Activity = new ActivityTemplate("done")
}
}
},
new OnIntent()
new OnIntent
{
Intent = "DeferToRecognizer_xxx",
Actions = new List<Dialog>()
Actions = new List<Dialog>
{
new SendActivity()
new SendActivity
{
Activity = new ActivityTemplate("DeferToRecognizer_xxx")
}
}
},
new OnUnknownIntent()
new OnUnknownIntent
{
Actions = new List<Dialog>()
Actions = new List<Dialog>
{
new SendActivity("Wha?")
}
Expand All @@ -227,13 +202,13 @@ private AdaptiveDialog CreateQnAMakerActionDialog(MockHttpMessageHandler mockHtt
return rootDialog;
}

private string GetV2LegacyRequestUrl() => $"{_hostname}/v2.0/knowledgebases/{_knowledgeBaseId}/generateanswer";
private string GetV2LegacyRequestUrl() => $"{Hostname}/v2.0/knowledgebases/{KnowledgeBaseId}/generateanswer";

private string GetV3LegacyRequestUrl() => $"{_hostname}/v3.0/knowledgebases/{_knowledgeBaseId}/generateanswer";
private string GetV3LegacyRequestUrl() => $"{Hostname}/v3.0/knowledgebases/{KnowledgeBaseId}/generateanswer";

private string GetRequestUrl() => $"{_hostname}/knowledgebases/{_knowledgeBaseId}/generateanswer";
private string GetRequestUrl() => $"{Hostname}/knowledgebases/{KnowledgeBaseId}/generateanswer";

private string GetTrainRequestUrl() => $"{_hostname}/knowledgebases/{_knowledgeBaseId}/train";
private string GetTrainRequestUrl() => $"{Hostname}/knowledgebases/{KnowledgeBaseId}/train";

private Stream GetResponse(string fileName)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
// Copyright (c) Microsoft Corporation. All righ reserved.
// Licensed under the MIT License.

using System;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xunit;

namespace Microsoft.Bot.Builder.AI.QnA.Tests
{
[TestClass]
public class QnAMakerSettingsTests
{
[TestMethod]
[TestCategory("AI")]
[TestCategory("QnAMaker")]
[Fact]
[Trait("TestCategory ", "AI")]
[Trait("TestCategory ", "QnAMaker")]
public void QnAMakerSettings_GetUserJsonSettingFiles()
{
var builder = new ConfigurationBuilder();
Expand All @@ -24,7 +22,7 @@ public void QnAMakerSettings_GetUserJsonSettingFiles()
builder.UseQnAMakerSettings(botRoot, region, environment);

var source = builder.Sources[1] as Microsoft.Extensions.Configuration.Json.JsonConfigurationSource;
Assert.AreEqual("qnamaker.settings.development.westus.json", source.Path);
Assert.Equal("qnamaker.settings.development.westus.json", source.Path);
}
}
}
Loading