用于单元测试的域模型的接口/虚拟



我正在开发一个.Net Core Web应用程序,该应用程序正在使用NUnit和Moq进行单元测试。为了便于提问,下面的例子非常简单。

我有一个"purchaseOrderService"类,它从存储库中获取采购订单并调用

purchaseOrder.Cancel();

然后保存到存储库。PurchaseOrder和StockItem类别如下,

public class PurchaseOrder
{
public int Id { get; set; }
public List<StockItem> StockItems { get; set; }
public PurchaseOrderStatus Status { get; private set; }
public void Cancel()
{
Status = PurchaseOrderStatus.Cancelled;
foreach(var stockItem in StockItems)
stockItem.Cancel();
}
}
public class StockItem
{
public int Id { get; set; }
public StockItemStatus Status { get; private set; }
public void Cancel()
{
Status = StockItemStatus.Cancelled;
}
}

在我的purchaseOrder.Cancel方法的单元测试中,我想模拟stockItem,这样我就可以验证Cancel Cancel方法是否对采购订单中的每个stockItem调用了一次。

我通常会用这样的东西来实现这一点。

Mock<StockItem> mockSI = new Mock<StockItem>();
mockSI.Setup(x => x.Cancel());
mockSI.Setup( x=> x.Cancel(), Times.Once);

但是,域模型不是作为接口公开的,Cancel方法也不是虚拟的,因此不能为了Mock的目的而重写Cancel方法。

这给我留下了3个选项

  1. 将cancel方法设为虚拟方法-这似乎是一个可怕的想法,并使其在不需要的时候被覆盖。

  2. 为需要模拟的域模型制作一个接口-这似乎太过分了,因为我只会制作用于测试的接口,而没有计划让任何其他类继承接口,并且在我完全控制的类上。StackOverflow上的多篇帖子说,没有充分理由的域模型接口是不好的做法。

例如,富域模型的接口

  1. 将其视为一个集成测试,并测试两个共同工作的类

目前我倾向于让StockItem类实现一个接口。你推荐什么?

这里不需要实现接口。

只需要重新思考如何验证预期行为。

在取消采购订单后检查项目的状态,这应该足以指示/验证是否调用了StockItem.Cancel

[Test]
public void StockItem_Should_Cancel_When_PurchaseOrder_Cancelled() {
//Arrange
var item = new StockItem();
var purchaseOrder = new PurchaseOrder() {
StockItems = new List<StockItem> { 
item
}
};
//Act
purchaseOrder.Cancel();
//Assert
item.Status.Should().Be(StockItemStatus.Cancelled);
}

最新更新