无法理解最小起订量

Trouble understanding Moq

我无法掌握 Moq 框架。他们从最小起订量网站给出了这个例子...

// Assumptions:
public interface IFoo {
   public bool DoSomething(string);
   public bool TryParse(string, out string));
}

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);

Moq 设置在这里做什么?

// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);

同样的问题..正在设置什么?

有谁知道可能更深入的最小起订量指南?我读了这本 SO post where the book The Art of Unit Testing with Examples in .NET 推荐,但是这本书很旧,已经绝版了。

对于模拟的一般背景,this answer 很好地解释了它以及为什么您可能想在单元测试中使用它。

具体来说,Moq 是一个允许您轻松创建模拟对象并控制其行为的库。用例子描述是最简单的,所以让我们看看你的第一个代码示例:

public interface IFoo {
   public bool DoSomething(string);
   public bool TryParse(string, out string));
}

/* 1 */ var mock = new Mock<IFoo>();
/* 2 */ mock.Setup(foo => foo.DoSomething("ping")).Returns(true);

第 1 行创建 IFoo 接口的 模拟实现 。在幕后,Moq 正在使用 Castle DynamicProxy 库动态创建 IFoo 的具体实现,然后将其包装在自己的 Mock class 中,以便我们可以配置它的行为。

现在我们有了一个模拟对象,我们将经常需要配置它如何响应调用其方法。这样,我们就可以测试我们的被测系统将如何对其做出反应。第 2 行的 Setup 方法正是这样做的,它告诉我们的模拟对象 return true 当使用等于 "ping" 的参数调用 DoSomething 时。假设您正在使用此模拟来测试 class,如下所示:

public class TestObject 
{
    public string TestMethod(IFoo foo)
    {
        if (foo.DoSomething("ping"))
            return "ping";
        else if (foo.DoSomething("pong"))
            return "pong";
        return "blah";
    }
}

要获得完整的测试覆盖率,您需要 IFoo 的实现可以:

  1. return true 一次测试 "ping"
  2. return true 在另一个测试中 "pong"
  3. return false 对于上次测试中的任何参数

可以创建您自己的具有此行为的模拟对象,例如:

public class MockFoo : IFoo
{
    string trueValue;

    public MockFoo(string trueValue)
    {
        this.trueValue = trueValue;
    }

    public bool DoSomething(string value)
    {
        return value == trueValue;
    }
}

但是当您有复杂的逻辑、多个参数或许多依赖项时,这会很痛苦;它只是不能很好地扩展。这就是模拟对象和 Moq 可以使事情变得简单的地方。三个测试在最小起订量中的相同设置是:

  1. mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
    
  2. mock.Setup(foo => foo.DoSomething("pong")).Returns(true);
    
  3. mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Returns(false);
    

在我看来,这更简单也更能表达您对 IFoo 依赖行为的期望。

至于指南,我认为您最好使用一般模拟指南而不是 Moq-specific 指南。 Moq 只是一个使模拟对象的使用更容易的库,Quickstart is a pretty good reference for the mechanics of using Moq. There are dozens of mocking tutorials and guides, just look for some. And remember, it didn't really "click" for me until I started using them. Find a coding kata 并尝试自己模拟!