Conversations.SendToConversationAsync在单元测试中崩溃 [英] Conversations.SendToConversationAsync crashes on Unit testing
问题描述
我在控制器中有以下方法可以从控制器本身发送消息(当用户添加漫游器时说欢迎消息)
private static async Task<string> OnSendOneToOneMessage(Activity activity,
IList<Attachment> attachments = null)
{
var reply = activity.CreateReply();
if (attachments != null)
{
reply.Attachments = attachments;
}
if (_connectorClient == null)
{
_connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
}
var resourceResponse = await _connectorClient.Conversations.SendToConversationAsync(reply);
return resourceResponse.Id;
}
单元测试看起来像这样
[TestClass]
public sealed class MessagesControllerTest
{
[Test]
public async Task CheckOnContactRelationUpdate()
{
// Few more setup related to dB <deleted>
var activity = new Mock<Activity>(MockBehavior.Loose);
activity.Object.Id = activityMessageId;
activity.Object.Type = ActivityTypes.ContactRelationUpdate;
activity.Object.Action = ContactRelationUpdateActionTypes.Add;
activity.Object.From = new ChannelAccount(userId, userName);
activity.Object.Recipient = new ChannelAccount(AppConstants.BotId, AppConstants.BotName);
activity.Object.ServiceUrl = serviceUrl;
activity.Object.ChannelId = channelId;
activity.Object.Conversation = new ConversationAccount {Id = Guid.NewGuid().ToString()};
activity.Object.Attachments = Array.Empty<Attachment>();
activity.Object.Entities = Array.Empty<Entity>();
var messagesController =
new MessagesController(mongoDatabase.Object, null)
{
Request = new HttpRequestMessage(),
Configuration = new HttpConfiguration()
};
// Act
var response = await messagesController.Post(activity.Object);
var responseMessage = await response.Content.ReadAsStringAsync();
// Assert
Assert.IsNotEmpty(responseMessage);
}
}
当用户添加bor时,OnSendOneToOneMessage方法可以正常工作.但是对于单元测试,它会崩溃.似乎我缺少POST的某些设置?
堆栈跟踪为
Result StackTrace:
at System.Net.Http.StringContent.GetContentByteArray(String content, Encoding encoding)
at System.Net.Http.StringContent..ctor(String content, Encoding encoding, String mediaType)
at System.Net.Http.StringContent..ctor(String content)
at <>.Controllers.MessagesController.<Post>d__4.MoveNext() in
C:\Users....MessagesController.cs:line 75
-从上一个引发异常的位置开始的堆栈结束- 在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()处 在BotTest.Controllers.MessagesControllerTest.d__0.MoveNext()中 C:\ Users .... MessagesControllerTest.cs:第75行 ---从上一个引发异常的位置开始的堆栈结束跟踪--- 在NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitFor PendingOperationsToComplete(Object invocationResult) 在NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext上下文) 结果消息: System.ArgumentNullException:值不能为null. 参数名称:内容
这是输出
Exception thrown: 'System.ArgumentNullException' in mscorlib.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in Microsoft.Rest.ClientRuntime.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in mscorlib.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in Microsoft.Rest.ClientRuntime.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in mscorlib.dll
Exception thrown: 'System.Net.Http.HttpRequestException' in System.Net.Http.dll
Exception thrown: 'System.UnauthorizedAccessException' in Microsoft.Bot.Connector.dll
Exception thrown: 'System.UnauthorizedAccessException' in mscorlib.dll
Exception thrown: 'System.UnauthorizedAccessException' in System.Net.Http.dll
Exception thrown: 'System.UnauthorizedAccessException' in mscorlib.dll
Exception thrown: 'System.UnauthorizedAccessException' in mscorlib.dll
注意:我试图以各种不同的方式传递证书.仍然会在单元测试时崩溃.
根据您的评论,您似乎想做的是功能/集成测试.
为此,我建议使用直接线.唯一需要注意的是,该机器人需要托管,但它确实功能强大.该方法包括使用Direct Line将消息发送到托管的bot,捕获响应并根据这些Bot测试用例进行断言.
查看所有实现的最佳方法是检出 AzureBot测试项目.遵循这种方法进行了大量的功能测试.
美丽之处在于测试非常简单,它们只是定义了场景:
public async Task ShoudListVms()
{
var testCase = new BotTestCase()
{
Action = "list vms",
ExpectedReply = "Available VMs are",
};
await TestRunner.RunTestCase(testCase);
}
所有的魔力都发生在 TestRunner 中. BotHelper 类具有与直线的所有交互,它在 General 类中进行配置和初始化
我知道这有很多要消化的地方,您将需要在这里和那里进行一些更改,但是我认为,如果您花些时间掌握这一点,它将确实帮助您进行一流的功能测试./p>
I have the following method in the controller to send a message from the controller itself (Say a welcome message when a user adds the bot)
private static async Task<string> OnSendOneToOneMessage(Activity activity,
IList<Attachment> attachments = null)
{
var reply = activity.CreateReply();
if (attachments != null)
{
reply.Attachments = attachments;
}
if (_connectorClient == null)
{
_connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl));
}
var resourceResponse = await _connectorClient.Conversations.SendToConversationAsync(reply);
return resourceResponse.Id;
}
And the unit test looks like this
[TestClass]
public sealed class MessagesControllerTest
{
[Test]
public async Task CheckOnContactRelationUpdate()
{
// Few more setup related to dB <deleted>
var activity = new Mock<Activity>(MockBehavior.Loose);
activity.Object.Id = activityMessageId;
activity.Object.Type = ActivityTypes.ContactRelationUpdate;
activity.Object.Action = ContactRelationUpdateActionTypes.Add;
activity.Object.From = new ChannelAccount(userId, userName);
activity.Object.Recipient = new ChannelAccount(AppConstants.BotId, AppConstants.BotName);
activity.Object.ServiceUrl = serviceUrl;
activity.Object.ChannelId = channelId;
activity.Object.Conversation = new ConversationAccount {Id = Guid.NewGuid().ToString()};
activity.Object.Attachments = Array.Empty<Attachment>();
activity.Object.Entities = Array.Empty<Entity>();
var messagesController =
new MessagesController(mongoDatabase.Object, null)
{
Request = new HttpRequestMessage(),
Configuration = new HttpConfiguration()
};
// Act
var response = await messagesController.Post(activity.Object);
var responseMessage = await response.Content.ReadAsStringAsync();
// Assert
Assert.IsNotEmpty(responseMessage);
}
}
The method OnSendOneToOneMessage works fine when a user adds the bor. But it crashes for the unit test. Seems i am missing some setup for the POST?
The stack trace is
Result StackTrace:
at System.Net.Http.StringContent.GetContentByteArray(String content, Encoding encoding)
at System.Net.Http.StringContent..ctor(String content, Encoding encoding, String mediaType)
at System.Net.Http.StringContent..ctor(String content)
at <>.Controllers.MessagesController.<Post>d__4.MoveNext() in
C:\Users....MessagesController.cs:line 75
--- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at BotTest.Controllers.MessagesControllerTest.d__0.MoveNext() in C:\Users....MessagesControllerTest.cs:line 75 --- End of stack trace from previous location where exception was thrown --- at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitFor PendingOperationsToComplete(Object invocationResult) at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context) Result Message: System.ArgumentNullException : Value cannot be null. Parameter name: content
And here is the output
Exception thrown: 'System.ArgumentNullException' in mscorlib.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in Microsoft.Rest.ClientRuntime.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in mscorlib.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in Microsoft.Rest.ClientRuntime.dll
Exception thrown: 'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException' in mscorlib.dll
Exception thrown: 'System.Net.Http.HttpRequestException' in System.Net.Http.dll
Exception thrown: 'System.UnauthorizedAccessException' in Microsoft.Bot.Connector.dll
Exception thrown: 'System.UnauthorizedAccessException' in mscorlib.dll
Exception thrown: 'System.UnauthorizedAccessException' in System.Net.Http.dll
Exception thrown: 'System.UnauthorizedAccessException' in mscorlib.dll
Exception thrown: 'System.UnauthorizedAccessException' in mscorlib.dll
NOTE: I tried passing the credential in all different ways. Still it crashes on unit testing.
Based on your comments, it seems that what you want to do is functional/integration testing.
For that, I would recommend using Direct Line. The only caveat is that the bot would need to be hosted but it's really powerful. The approach consist of using Direct Line to send messages to the hosted bot, capture the response and do asserts based on those Bot test cases.
The best way to see all this implemented is by checking out the AzureBot tests project. There tons of functional tests following this approach.
The beauty is that test are extremely simple, they just define the scenario:
public async Task ShoudListVms()
{
var testCase = new BotTestCase()
{
Action = "list vms",
ExpectedReply = "Available VMs are",
};
await TestRunner.RunTestCase(testCase);
}
All the magic happens in the TestRunner. The BotHelper class has all the interactions with Direct Line, which is configured and initialized in the General class.
I know this is lot to digest, and that you will need to change things here and there, but I think that if you take the time to master this out, it will really help you to do first class functional tests.
这篇关于Conversations.SendToConversationAsync在单元测试中崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!