简体   繁体   English

单个方法或通用 It.IsAny 的模拟行为松散

[英]Mock behavior loose for single method or generic It.IsAny

I have an abstract class Shape and a couple of classes inheriting from it ( Square , Rectangle , Triangle , Circle , ...).我有一个抽象类Shape和几个继承自它的类( SquareRectangleTriangleCircle ,...)。 I also have an AreaCalculator class, which contains a method named CalculateAreasByShape() .我还有一个AreaCalculator类,其中包含一个名为CalculateAreasByShape()的方法。 This method calls a series of CalculateShapeAreas<TShape>(List<TShape> shapes) methods for each Shape type.此方法为每个Shape类型调用一系列CalculateShapeAreas<TShape>(List<TShape> shapes)方法。

Now, in my unit tests, I have the following code:现在,在我的单元测试中,我有以下代码:

...
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();
...

This code fails on the fact, that MockBehavior is set to Strict and there is no setup for the CalculateShapeAreas<TShape>() methods.这段代码失败了,因为MockBehavior设置为Strict并且没有设置CalculateShapeAreas<TShape>()方法。 Now, I know I could run a setup for each of the Shape types, eg:现在,我知道我可以为每个 Shape 类型运行一个设置,例如:

areaMock.Setup(m => m.CalculateShapeAreas<Triangle>(It.IsAny<List<Triangle>>())).Returns(default(decimal));

But this will create a lot of duplicate code.但这会产生很多重复的代码。 I wonder whether we can use the fact that all shapes inherit from the same base class.我想知道我们是否可以使用所有形状都继承自同一个基类的事实。 I have tried the following, but it does not work:我尝试了以下方法,但不起作用:

areaMock.Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<List<Shape>>())).Returns(default(decimal));

Alternatively, is it possible to set MockBehavior.Loose on a single generic method (meaning, it would not check the actual type)?或者,是否可以在单个泛型方法上设置MockBehavior.Loose (也就是说,它不会检查实际类型)?

It.IsAny for open generic support is not yet present in the moq (release 4.12.0). It.IsAny开放的通用支持尚不存在于moq (版本4.12.0)。 Eventually there are some plans to introduce this, take a look here最终有一些计划介绍这个,看看这里


I think problem you are facing is because you are using List<T> as an input parameter.我认为您面临的问题是因为您使用List<T>作为输入参数。 As you might notice List<T> is not covariant.您可能会注意到List<T>不是协变的。

What that mean?那是什么意思?

List<Shape> shapeList;
IEnumerable<Shape> shapeEnumerable;
var triag = new List<Triangle>();

shapeList = triag; // NOT ALLOWED
shapeEnumerable = triag; // ALLOWED

The same makes problem while mocking.嘲笑时同样会产生问题。 One solution could be to change interface and instead of passing List<T> pass IEnumerable<out T> , or as @JeppeStigNielsen pointed out IReadOnlyList<out T> .一种解决方案可能是更改interface ,而不是传递List<T>传递IEnumerable<out T> ,或者正如@JeppeStigNielsen 指出的那样IReadOnlyList<out T> In fact any covariant in T interface which is implemented by List<T> could be used.实际上,可以使用由List<T>实现的T接口中的任何协变。

areaMock
    .Setup(m => m.CalculateShapeAreas<Shape>(It.IsAny<IEnumerable<Shape>>()))
    .Returns(default(decimal));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM