Conversations.SendToConversationAsync在单元测试中崩溃 [英] Conversations.SendToConversationAsync crashes on Unit testing

查看:102
本文介绍了Conversations.SendToConversationAsync在单元测试中崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在控制器中有以下方法可以从控制器本身发送消息(当用户添加漫游器时说欢迎消息)

        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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆