单一方法或泛型的模拟行为松散 It.IsAny
Mock behavior loose for single method or generic It.IsAny
我有一个摘要 class Shape
和几个继承自它的 classes (Square
, Rectangle
, Triangle
, Circle
, ...)。我还有一个 AreaCalculator
class,其中包含一个名为 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>()
方法。现在,我知道我可以 运行 每个形状类型的设置,例如:
areaMock.Setup(m => m.CalculateShapeAreas<Triangle>(It.IsAny<List<Triangle>>())).Returns(default(decimal));
但这会产生很多重复代码。我想知道我们是否可以利用所有形状都继承自相同基数的事实 class。我尝试了以下方法,但它不起作用:
areaMock.Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<List<Shape>>())).Returns(default(decimal));
或者,是否可以在单个泛型方法上设置 MockBehavior.Loose
(意思是,它不会检查实际类型)?
It.IsAny
开放通用支持尚未出现在 moq
(版本 4.12.0)中。终于有计划介绍这个了,看看here
我认为您面临的问题是因为您使用 List<T>
作为输入参数。您可能会注意到 List<T>
不是协变的。
什么意思?
List<Shape> shapeList;
IEnumerable<Shape> shapeEnumerable;
var triag = new List<Triangle>();
shapeList = triag; // NOT ALLOWED
shapeEnumerable = triag; // ALLOWED
模拟时同样会产生问题。一种解决方案可能是更改 interface
而不是传递 List<T>
传递 IEnumerable<out T>
,或者正如@JeppeStigNielsen 指出的那样 IReadOnlyList<out T>
。事实上,可以使用由 List<T>
实现的 T
接口中的任何协变。
areaMock
.Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<IEnumerable<Shape>>()))
.Returns(default(decimal));
我有一个摘要 class Shape
和几个继承自它的 classes (Square
, Rectangle
, Triangle
, Circle
, ...)。我还有一个 AreaCalculator
class,其中包含一个名为 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>()
方法。现在,我知道我可以 运行 每个形状类型的设置,例如:
areaMock.Setup(m => m.CalculateShapeAreas<Triangle>(It.IsAny<List<Triangle>>())).Returns(default(decimal));
但这会产生很多重复代码。我想知道我们是否可以利用所有形状都继承自相同基数的事实 class。我尝试了以下方法,但它不起作用:
areaMock.Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<List<Shape>>())).Returns(default(decimal));
或者,是否可以在单个泛型方法上设置 MockBehavior.Loose
(意思是,它不会检查实际类型)?
It.IsAny
开放通用支持尚未出现在 moq
(版本 4.12.0)中。终于有计划介绍这个了,看看here
我认为您面临的问题是因为您使用 List<T>
作为输入参数。您可能会注意到 List<T>
不是协变的。
什么意思?
List<Shape> shapeList;
IEnumerable<Shape> shapeEnumerable;
var triag = new List<Triangle>();
shapeList = triag; // NOT ALLOWED
shapeEnumerable = triag; // ALLOWED
模拟时同样会产生问题。一种解决方案可能是更改 interface
而不是传递 List<T>
传递 IEnumerable<out T>
,或者正如@JeppeStigNielsen 指出的那样 IReadOnlyList<out T>
。事实上,可以使用由 List<T>
实现的 T
接口中的任何协变。
areaMock
.Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<IEnumerable<Shape>>()))
.Returns(default(decimal));