Dam*_*amo 3 .net c# unit-testing moq nservicebus
问题
如果当前正在测试的方法是通过传入消息(进入处理程序)之外的其他方法启动的,那么如何测试事件的发布。NServiceBus.Testing 的问题(据我所知)是它非常适合测试处理程序,从而导致消息/事件被发送/发布。
背景:
我们有许多遗留系统,在持续努力转向正确的 SOA 实施的过程中,我们需要与一些遗留数据库作业集成。这些作业每 15 分钟对数据库执行一次操作,我们希望在发生某些条件时挂钩并发布事件。
我们有一个在 NsbHost 内运行的 Windows 服务,但不包含任何处理程序。相反,我们使用 Quartz 创建一个每分钟运行一次的内部 cron 作业,轮询数据库以查找与指定模式匹配的记录,并在更新数据库之前发布一个事件,表明我们已经处理了该记录。这就是我们整合新旧系统的方式。
显然,这不是一个理想的情况,但考虑到我们正处于 SOA 实施的过渡阶段,它和我们现在一样好。
详细信息和代码:
我们正在发布的事件界面如下所示
public interface IPremiumAdjustmentFinalised
{
string PolicyNumber { get; set; }
decimal Amount { get; set; }
DateTime FinalisedOn { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
实际发布事件的代码是
Bus.Publish<IPremiumAdjustmentFinalised>(e =>
{
e.Amount = AdjustmentAmount;
e.PolicyNumber = PolicyNumber;
e.FinalisedOn = LastModifiedOn;
});
Run Code Online (Sandbox Code Playgroud)
这一切都工作正常,我们可以测试使用最小起订量进行的调用,如下所示:
eventPublisher.MethodToTest();
bus.Verify(x => x.Publish(It.IsAny<Action<IPremiumAdjustmentFinalised>>()), Times.Once);
Run Code Online (Sandbox Code Playgroud)
其中bus是插入到构造函数中的新Mock。
但我想测试 IPremiumAdjustmentFinalized 中的值。我发现这真的很困难,我认为主要是因为它是一个接口而不是一个具体的类。
我们尝试使用 NServiceBus.Testing 来尝试检查生成的事件,但无济于事。
有谁知道如何在给定场景中测试事件中的值?
我们提出了 2 个解决方案
解决方案一:
创建一个继承接口并总线发布的具体类
public class PremiumAdjustmentFinalisedEvent : IPremiumAdjustmentFinalised
{
public string PolicyNumber { get; set; }
public decimal Amount { get; set; }
public DateTime FinalisedOn { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
此类仅在发送方中使用,另一端的处理程序仍会侦听 IPremiumAdjustmentFinalished 类型的事件。
发送事件将更改为这样
var message = new PremiumAdjustmentFinalisedEvent
{
Amount = AdjustmentAmount,
PolicyNumber = PolicyNumber,
FinalisedOn = LastModifiedOn
};
Bus.Publish<IPremiumAdjustmentFinalised>(message);
Run Code Online (Sandbox Code Playgroud)
这使我们能够测试:
bus.Verify(x => x.Publish(It.Is<IPremiumAdjustmentFinalised>(paf =>
paf.Amount == AdjustmentAmount &&
paf.FinalisedOn == LastModifiedOn &&
paf.PolicyNumber == PolicyNumber)), Times.Once);
Run Code Online (Sandbox Code Playgroud)
这不是一个理想的解决方案,因为我们需要向实时解决方案添加代码以启用测试,但它运行良好且易于理解。
解决方案2:
实现我们自己的 IBus 并断言对象是正确的:
class myBus : IBus
{
public void Publish<T>(Action<T> messageConstructor)
{
IPremiumAdjustmentFinalised paf = new PremiumAdjustmentFinalised();
var ipaf = (T) paf;
messageConstructor(ipaf);
Assert.AreEqual(paf.Amount, AdjustmentAmount);
Assert.AreEqual(paf.FinalisedOn, LastModifiedOn);
Assert.AreEqual(paf.PolicyNumber, PolicyNumber);
}
...
<<Leave the rest of the methods not implemented>>
...
}
Run Code Online (Sandbox Code Playgroud)
使用我自己的 IPremiumAdjustmentFinalized 测试实现(类似于解决方案 1,但在测试项目中)
现在测试看起来像这样
var myBus = new myBus();
eventPublisher = new AdjustmentFinaliserEventPublisher(myBus);
eventPublisher.UpdateAndPublishFinalisedAdjustments();
Run Code Online (Sandbox Code Playgroud)
我喜欢这个解决方案,因为它不会仅仅为了测试而更改实时代码,但缺点是 IBus 的实现很大,上面有大量未实现的方法。
| 归档时间: |
|
| 查看次数: |
2394 次 |
| 最近记录: |