简体   繁体   English

Mock上的设置未返回预期值

[英]Setup on Mock not returning expected value

Here is a simplified version of a problem I encountered: 这是我遇到的问题的简化版本:

public interface IService
{
    IProvider Provider { get; }
}

public interface IProvider
{
    List<int> Numbers{ get; }
    string Text { get; }
} 

[TestMethod]
public void ServiceTest()
{
    var service = new Mock<IService>();
    var provider = new Mock<IProvider>();

    service.Setup(s => s.Provider).Returns(provider.Object);    // A
    service.Setup(s => s.Provider.Text).Returns("some text");   // B - incorrect

    // they actually meant to do this, instead of 'B'
    // provider.Setup(p => p.Text).Returns("some text"); 

    provider.Setup(p => p.Numbers).Returns(new List<int> { 1, 2, 3 });

    DummyApplicationCode(service.Object);
}

int DummyApplicationCode(IService service)
{
    // will throw, because the Provider was replaced at 'B'
    int shouldBeOne = service.Provider.Numbers.First(); 
    return shouldBeOne;
}

A unit test was failing because way down in the application code under test, the mocked IService was returning the wrong IProvider . 单元测试失败了,因为在测试的应用程序代码中,被模拟的IService返回了错误的IProvider

I eventually spotted the line ( bear in mind the code I was looking at was not as simple as above ) which had caused it, labelled 'B' above, which someone else had added due to misunderstanding the Moq Setup. 我最终发现这条线( 记住我看到的代码并不像上面那么简单 )导致它,上面标有“B”,由于误解了Moq设置,其他人添加了。

I'm aware that subsequent Setups on a mock will override previous ones but I hadn't spotted this issue because the Return of the offending line was for a separate sub-property. 我知道模拟的后续设置会覆盖以前的设置,但我没有发现这个问题,因为违规行的返回是针对一个单独的子属性。

I expect this is by design but it threw me as I hadn't anticipated someone would do this. 我希望这是设计但它扔给我,因为我没想到有人会这样做。

My question : Since the Setup at 'B' is only concerned with the return of the provider Text , why does the service 'Provider' property need to replace that which was defined at 'A'? 我的问题 :由于'B'的设置仅涉及提供者Text的返回,为什么服务'Provider'属性需要替换'A'中定义的属性?

This is clearly intentional when looking at the source: 在查看来源时,这显然是有意的:

https://github.com/moq/moq4/blob/master/Source/Mock.cs https://github.com/moq/moq4/blob/master/Source/Mock.cs

https://github.com/moq/moq4/blob/master/Source/Interceptor.cs https://github.com/moq/moq4/blob/master/Source/Interceptor.cs

Setup creates a "call" by using AddCall on Interceptor . Setup通过在Interceptor上使用AddCall创建“调用”。 This contains the following block of code which, as long as we're creating a non-conditional setup, removes all previous setups. 这包含以下代码块,只要我们创建非条件设置,就会删除所有先前的设置。 It's even commented. 它甚至评论道。

if (!call.IsConditional)
            {
                lock (calls)
                {
                    // if it's not a conditional call, we do
                    // all the override setups.
                    // TODO maybe add the conditionals to other
                    // record like calls to be user friendly and display
                    // somethig like: non of this calls were performed.
                    if (calls.ContainsKey(key))
                    {
                        // Remove previous from ordered calls
                        InterceptionContext.RemoveOrderedCall(calls[key]);
                    }

                    calls[key] = call;
}

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

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