[英]Moq: strange parameter evaluation during mock Setup
This has caused me half a day of debugging and head-scratching.这让我调试了半天,头疼。 I'm using Moq 4.2.1408.0717.
我正在使用最小起订量 4.2.1408.0717。 I have a service, which is mocked.
我有一项被嘲笑的服务。 And then I have client which is again mocked, but one of the match attributes will use the (mocked) service for its evaluation.
然后我有客户端再次被嘲笑,但匹配属性之一将使用(模拟)服务进行评估。 Reduced example below:
下面的简化示例:
[TestFixture]
class PPAP
{
[Test]
public void Test_Apple_Pen()
{
var fruitMock = new Mock<IFruit>(); // the mocked service
fruitMock.Setup(x => x.GetFruit()).Returns("apple");
var fw = new FruitWrapper(fruitMock.Object); // object that uses the (mocked) service behind curtains
var uhhMock = new Mock<IUhh>();
uhhMock.Setup(x => x.Uhh(fw.GetFruit())).Returns("apple-pen");
// Utterly unimportant part below, added for clarity:
var result = uhhMock.Object.Uhh("apple");
Assert.That(result, Is.EqualTo("apple-pen"));
}
}
public interface IFruit
{
string GetFruit();
}
public interface IUhh
{
string Uhh(string s);
}
public class FruitWrapper
{
private IFruit _fruit;
public FruitWrapper(IFruit fruit)
{
_fruit = fruit;
}
public string GetFruit()
{
var f = _fruit.GetFruit(); // f should never be null since I mocked it already!
// LOOK HERE *jumps and waves* THIS IS THE PROBLEM:
if (f == null) {
throw new Exception("POINT OF THE QUESTION HERE: Service mock doesn't function!!!");
}
return f; // yet this method will be called twice with f being null before finally called with f == "apple" during Setup()
}
}
Problem is, the code using the service (FruitWrapper in the example) is not prepared to receive null from the service (that's the point of mocking the service after all!).问题是,使用服务的代码(示例中的FruitWrapper)没有准备好从服务接收空值(毕竟这是模拟服务的重点!)。 Still, during the Setup() of the client mock (uhhMock in the example), FruitWrapper's GetFruit() will be called so that the service will return null (despite the mock already in place).
尽管如此,在客户端模拟(示例中的 uhhMock)的 Setup() 期间,将调用 FruitWrapper 的 GetFruit() 以便服务将返回 null(尽管模拟已经到位)。 This was killing my test with an exception.
除了一个例外,这杀死了我的测试。 I still have no idea why is this happening.
我仍然不知道为什么会这样。 Is this normal behavior or is this a Moq bug?
这是正常行为还是 Moq 错误?
(Now that with the reduced example the test doesn't die on null from service, I see that finally the match parameter is evaluated correctly.) Edit: the example was modified to not survive null from service.(现在使用简化的示例,测试不会因服务为空而死亡,我看到最终匹配参数被正确评估。)
编辑:该示例已修改为无法从服务中获得空值。 If it did, finally there would be a call where the service returns non-null.
如果是这样,最后会有一个服务返回非空值的调用。
(Of course, if I save the parameter (fw.GetFruit()) to a variable before the Setup and use that inside, then everything's fine.) (当然,如果我在 Setup 之前将参数 (fw.GetFruit()) 保存到一个变量中并在内部使用它,那么一切都很好。)
Edit: since people have trouble understanding what I mean.编辑:因为人们难以理解我的意思。 I added some code:
我添加了一些代码:
I'm not sure what your test is supposed to be doing.我不确定你的测试应该做什么。 Is it a complete test?
是完整的测试吗?
var uhhMock = new Mock<IUhh>();
uhhMock.Setup(x => x.Uhh(fw.GetFruit())).Returns("apple-pen");
Change this to use the actual value you want to Setup on:将此更改为使用要设置的实际值:
var uhhMock = new Mock<IUhh>();
uhhMock.Setup(x => x.Uhh("apple")).Returns("apple-pen");
Another problem is that it appears you're doing some sort of integration test with multiple layers of mocks (using a mock IUhh
to get a value from a concrete FruitWrapper
which has a mock IFruit
).另一个问题是,您似乎正在对多层模拟进行某种集成测试(使用模拟
IUhh
从具有模拟IFruit
的具体FruitWrapper
获取值)。 Try to break it down to using the class under test with mock dependencies.尝试将其分解为使用带有模拟依赖项的测试类。
A good idea is to use the AAA (Arrange, Act, Assert) pattern.一个好主意是使用 AAA(安排、行动、断言)模式。 For example:
例如:
[Test]
public void Test_Apple_Pen()
{
//Arrange
var fruitMock = new Mock<IFruit>();
fruitMock.Setup(x => x.GetFruit()).Returns("apple");
var fw = new FruitWrapper(fruitMock.Object);
//Act
var result = fw.GetFruit();
//Assert
Assert.AreEqual("apple", result);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.