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

时间:2018-10-29 21:55:29

标签: c# unit-testing interface moq

我正在开发一个.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,以便可以验证是否对采购订单中的每个stockItem调用一次cancel cancel方法。

我通常会用类似的方法实现这一目标。

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

但是,域模型没有作为接口公开,并且Cancel方法不是虚拟的,因此就模拟而言,不能重写Cancel方法。

这给了我3个选择

  1. 将cancel方法设为Virtual-这似乎是一个可怕的主意,并使其在不需要的时间被覆盖。

  2. 为需要模拟的域模型创建接口-这似乎过多,因为我将仅在没有计划让任何其他类继承该接口的情况下才进行测试,而我完全可以控制这些类。 StackOverflow上的多篇文章都说,没有充分理由的域模型接口是不好的做法。

例如, Interfaces for Rich Domain Models

  1. 将此作为更多的集成测试来对待,并测试两个类是否可以协同工作

此刻,我倾向于使StockItem类实现一个接口。你会推荐什么?

1 个答案:

答案 0 :(得分:3)

无需在此处实现接口。

只需要重新考虑如何验证预期行为即可。

在取消购买订单后检查物品的状态,该状态应足以表明/验证已调用<template> <fragment> <td>{{size.x}}</td> <td>{{size.y}}</td> <td>{{size.z}}</td> <td>{{volume}}</td> </fragment> </template> <script> import { Fragment } from 'vue-fragment'; export default { computed: { volume() { return this.size.x * this.size.y * this.size.z }, }, components: { Fragment }, props: ['size'] } </script>

StockItem.Cancel