【发布时间】:2019-07-25 19:03:53
【问题描述】:
我有一个抽象类Shape 和几个继承自它的类(Square、Rectangle、Triangle、Circle,...)。我还有一个AreaCalculator 类,其中包含一个名为CalculateAreasByShape() 的方法。此方法为每个Shape 类型调用一系列CalculateShapeAreas<TShape>(List<TShape> shapes) 方法。
现在,在我的单元测试中,我有以下代码:
...
var areaMock = new Mock<AreaCalculator>(MockBehavior.Strict);
areaMock.Setup(m => m.CalculateAreasByShape()).Returns(new Dictionary<Type, decimal>());
var canvas = new DemoCanvas(shapes, perimeterMock.Object, areaMock.object);
var result = canvas.RunShapeCalculations();
...
此代码失败的事实是,MockBehavior 设置为 Strict 并且没有设置 CalculateShapeAreas<TShape>() 方法。现在,我知道我可以为每种 Shape 类型运行设置,例如:
areaMock.Setup(m => m.CalculateShapeAreas<Triangle>(It.IsAny<List<Triangle>>())).Returns(default(decimal));
但这会产生很多重复的代码。我想知道我们是否可以使用所有形状都继承自同一个基类的事实。我尝试了以下方法,但它不起作用:
areaMock.Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<List<Shape>>())).Returns(default(decimal));
或者,是否可以在单个泛型方法上设置MockBehavior.Loose(也就是说,它不会检查实际类型)?
【问题讨论】:
-
你为什么不模拟接口而不是类呢?喜欢;
new Mock<IAreaCalculator>? -
因为在测试的后期我还断言
AreaCalculator中不同方法的调用次数,它们相互调用。我跳过了一些设置,以避免在我的问题中出现不必要的代码。 -
AFAIK,您需要摆脱
MockBehavior.Strict才能做到这一点,然后该类应标记为虚拟。我一直担心您的代码库的简单性,这就是为什么要求提供接口。编码愉快。 -
类似于Mocking generic methods in Moq without specifying T中描述的问题。就像 Moq 具有用于常用参数的
It.IsAny<>魔法一样,如果它具有用于类型参数的Moq.AnyType那就太好了。然后你可以这样做,例如mock.Setup(pa => pa.Reserve<Moq.AnyType>()).Returns(...)。在您的示例中,areaMock.Setup(m => m.CalculateShapeAreas<Moq.AnyType>(It.IsAny<List<Moq.AnyType>>())).Returns(default(decimal));实际上可以推断出第一个Moq.AnyType。但是如果类型需要约束呢? -
@JeppeStigNielsen 最终会是github.com/moq/moq4/issues/343
标签: c# unit-testing moq