NServiceBus 2.5.0.1442单元测试Bus.CreateInstance <interface>在某些单元测试中返回null </interface>

时间:2014-06-13 02:58:03

标签: c# unit-testing nservicebus

我在使用Sagas进行NServiceBus单元测试时遇到了奇怪的行为。

正在运行

  • NSB 2.5.0.1442(由于IMessage而被困在这里,并且它在多个服务中)
  • NServiceBus.Testing
  • Resharper 8.2 unit test runner
  • VS2013更新最新的rtm版本/ package / thingy

我的解决方案中有三个单元测试项目。其中只有一个引用了NServiceBus.Testing,因为它是唯一一个测试Saga的人。

  1. Messages.Testing
  2. Service.Testing(这个引用NSB.Testing)
  3. ViewModelUpdater.Testing
  4. 单独运行单元测试项目一切正常。

    将所有三个一起运行会在Service.Testing中引入一些测试失败。即使在调试模式下运行所有​​项目单元测试也会产生同样的问题。

    我已将问题回溯到此代码。我已经添加了命令== null检查以使单元测试失败,而不是返回愚蠢的rhino.mocks失败。

    var command = Bus.CreateInstance<IEmailMessage>(a =>
    {
        a.ToAddress = toAddresses;
        a.FromAddress = _formServiceEmailAddress;
        a.Subject = emailSubject;
        a.Body = body.ToString();
        a.IsHtmlBody = true;
    });
    
    if (command == null)
    {
        throw new Exception("Email Message Failed to Create");
    }
    
    Bus.Send(command);
    

    我没有包含测试代码,因为我从单元测试中删除了我的.ExpectSend代码,而且它仍然在这里失败。

    Bus.CreateInstance<IEmailMessage> is returning null.
    

    总线不为空,我选择所有单元测试项目并运行调试。

    在写这个问题时,我可能会越来越接近解决这个问题。调试时,以下内容来自QuickWatching Bus

    ((IBusProxyc9a2035def74446cb4f71fea5bf76c47)(Bus))
    +       __interceptors  {Castle.Core.Interceptor.IInterceptor[1]}   Castle.Core.Interceptor.IInterceptor[]
    

    “CreateInstance”是否可能已被代理并且不再起作用?我不在我的传奇中的任何其他地方使用Bus.CreateInstance,但是这个IEMailMessage是唯一的接口(它被我们所有服务用于发送到标准电子邮件发件人服务。

    我只是重写了另一条消息,使用Bus.CreateInstance&lt;&gt;但这次是在一个物体上,并得到了同样的问题。

    我对Bus.Send做了同样的事情并没有得到同样的问题。

    我现在正在将原始代码更新为

    Bus.Send<IEmailMessage>(a =>
    {
        a.ToAddress = toAddresses;
        a.FromAddress = _formServiceEmailAddress;
        a.Subject = emailSubject;
        a.Body = body.ToString();
        a.IsHtmlBody = true;
    });
    

    运行单元测试,现在不会对该代码抛出异常。

    但现在我的单元测试没有超出我的期望。

    InitiatedTestSaga(command)
        .ExpectPublish<FinanceUserAccessFormSubmitted>(m => CompareSubmitted(m,command) )
        .ExpectPublish<AssignedToManager>(m =>
        {
            Console.WriteLine("AssignedToManager");
            return m.FormId == command.FormId;
    
        })
        .ExpectSend<CreateFormSummary>(m =>
        {
            Console.WriteLine("CreateFormSummary");
            return m.FormId == command.FormId;
    
        })
        .ExpectSend<CreateFormHistory>(m =>
        {
            Console.WriteLine("CreateFormHistory");
            return m.FormId == command.FormId;
    
        })
        .ExpectSend<UpdateFormSummary>(m =>
        {
            Console.WriteLine("UpdateFormSummary");
            return m.FormId == command.FormId;
    
        })
        .ExpectSend<IEmailMessage>(m =>
        {
            Console.WriteLine("IEmailMessage");
            return TestCommands.ExpectedReceipientIs(m, command.FormDetails.ManagerForApproval.EmailAddress);
        })      
        .ExpectReply<CompletionMessage>(m => m.ErrorCode == (int) ResponseCode.Success)
        .When(s => s.Handle(command));
    

    输出

    AssignedToManager
    CreateFormSummary
    CreateFormHistory
    UpdateFormSummary
    Rhino.Mocks.Exceptions.ExpectationViolationException : IBus.Send(callback method: <>c__DisplayClass2`1.<ExpectSend>b__1); Expected #1, Actual #0.
    

    其中说IEmailMessage从未发送过。

    是否可以使用Bus.Send&lt;&gt;是不同于Bus.Send的行为?现在发送的消息的顺序是否可能不同。在saga代码中,iemailMessage是最后一条消息,因此应该是单元测试收到的最后一条消息。

    所以要回溯一下。当我单独运行测试时会发生什么?这是相同单元测试的输出

    AssignedToManager
    CreateFormSummary
    CreateFormHistory
    UpdateFormSummary
    IEmailMessage
    ExpectedReceipientIs__["Manager@domain.com"]
    

    因此,当所有测试项目都运行时,我们仍然遇到问题。我想如果我改变了期望的顺序,测试可能在运行所有时运行,但是然后单独运行会失败。

    当改变IEmailMessage期望的顺序时,无论我把它放在哪个顺序(即使在发布期望之间),我都会收到此错误消息

    System.InvalidCastException : Unable to cast object of type 'CreateFormSummary' to type 'IEmailMessage'.
    

    所以现在我的问题看起来并不尊重它是一个界面。我将用具有相同属性的本地类替换IEmailMessage

    创建了这个

    public class EmailMessage : IEmailMessage
    {
        public string BCCAddress { get; set; }
        public string Body { get; set; }
        public string CCAddress { get; set; }
        public string FromAddress { get; set; }
        public bool IsHtmlBody { get; set; }
        public string Subject { get; set; }
        public string ToAddress { get; set; }
    }
    
    //replaced IEmailMessage with concrete
    Bus.Send<EmailMessage>(a =>
    {
        a.ToAddress = toAddresses;
        a.FromAddress = _formServiceEmailAddress;
        a.Subject = emailSubject;
        a.Body = body.ToString();
        a.IsHtmlBody = true;
    }); 
    
    //Run All Unit tests 
    //output of this unit test
    AssignedToManager
    CreateFormSummary
    CreateFormHistory
    UpdateFormSummary
    IEmailMessage
    ExpectedReceipientIs__["Manager@domain.com"]
    

    为了好玩,我决定将我的代码恢复到Bus.CreateInstance以查看它是否仍然失败。

    private void CreateAndSendEmail(string[] emailAddresses, string emailSubject, StringBuilder body)
    {           
        string toAddresses = String.Join(",", emailAddresses);
    
        var msg = Bus.CreateInstance<IEmailMessage>(a=> 
        {
            a.ToAddress = toAddresses;
            a.FromAddress = _formServiceEmailAddress;
            a.Subject = emailSubject;
            a.Body = body.ToString();
            a.IsHtmlBody = true;
        })  ;
    
        if (msg == null)
        {
            throw new Exception("msg is null");
        }
    
        Bus.Send(msg);
    }
    
    //Run All Unit Tests
    //output is this
    AssignedToManager
    CreateFormSummary
    CreateFormHistory
    UpdateFormSummary
    IEmailMessage
    ExpectedReceipientIs__
    ["Manager@wesleymission.org.au"]
    

    WT​​H?它的工作原理

    我做了什么?我不确定。

    我继续发布这个问题,因为其他人可能会通过我所做的箍。此外,NSB /特定团队可能会对此反馈表示赞赏。

    我不会轻易放弃

    坚持,我不相信我做错了什么,让我试着再次打破它。

    1. 关闭解决方案
    2. 删除所有调试文件夹,
    3. 删除所有obj文件夹。
    4. 重建解决方案
    5. 关闭现有的测试会话
    6. 重新运行所有单元测试 - 通过
    7. 单独运行单元测试项目 - 通过
    8. 所以我的具体EmailMessages仍然存在,但我不再指任何地方了。所以我可以杀了它。

      1. 删除了具体的EmailMessages
      2. 重新运行所有单元测试 - FAILS!
      3. 单独运行 - 通过
      4. 单元测试的输出是

        AssignedToManager
        CreateFormSummary
        CreateFormHistory
        UpdateFormSummary
        System.Exception : msg is null 
        

        Saga正在两个实例中调用Bus.CreateInstance

        解决方案

        创建接口的实现,然后不使用它。

1 个答案:

答案 0 :(得分:0)

解决方案

创建接口的实现,然后不使用它。