C# 和 Moq:如何验证实例方法是否调用了正确的辅助实例方法?

C# and Moq: How to validate an instance method is calling the proper secondary instance method?

我在使用 Ruby 等其他语言进行模拟方面有很多经验,但我是 C# 中的 Moq 新手,我正在尝试验证对我来说最基本的模拟:验证一个方法正在使用正确的参数调用正确的方法。

我有这个例子主题class

public class Subject
{
    int _age;

    public Subject(int age)
    {
        _age = age;
    }

    public void MainMethod()
    {
        if(_age <= 13)
        {
            KidMethod();
        }
        else
        {
            AdultMethod();
        }
    }

    public void KidMethod() {}
    public void AdultMethod() {}
}

我正在尝试创建这个测试:

[Test]
public void MainMethod_ShouldCallKidMethod_IfAgeBelow1()
{
    var subjectMock = new Mock<Subject>(12);
    subjectMock.Verify(subject => subject.KidMethod());
    subjectMock.MainMethod();
}

但显然我做错了什么,因为我得到了这个错误:

error CS1061: 'Mock' does not contain a definition for 'MainMethod' and no accessible extension method 'MainMethod' accepting a first argument of type 'Mock' could be found (are you missing a using directive or an assembly reference?)

我想我缺少对使用 Moq 模拟的一些基本理解解决这个例子将帮助我得到它。

我一直在检查 SO 中的类似问题,但我检查过的所有问题都涵盖了更具体的案例,我没有找到任何人解决这个一般的简单案例。

更新 1

正在编译:

[Test]
public void MainMethod_ShouldCallKidMethod_IfAgeBelow1()
{
    var subjectMock = new Mock<Subject>(12);
    subjectMock.Object.MainMethod();
    subjectMock.Verify(subject => subject.KidMethod());
}

但现在我有错误:

System.NotSupportedException : Unsupported expression: subject => subject.KidMethod() Non-overridable members (here: Subject.KidMethod) may not be used in setup / verification expressions.

看起来 Moq 不能与不能被覆盖的方法一起使用 1

有没有办法做我正在尝试的事情?

你的例子对我来说没有多大意义:你正试图模拟你正在测试的 class 的某些方法。下面是一个比较典型的例子。

您的 class 可能使用了一些接口:

public class Subject
{
    private readonly IHelper _helper;
    int _age;

    public Subject(IHelper helper, int age)
    {
        _helper = helper;
        _age = age;
    }

    public void MainMethod()
    {
        if(_age <= 13)
        {
            _helper.KidMethod();
        }
        else
        {
            _helper.AdultMethod();
        }
    }
}

因此您的测试将模拟该界面。这样我们就可以单独测试 Subject

[Test]
public void MainMethod_ShouldCallKidMethod_IfAgeBelow1()
{
    // Arrange.
    var helperMock = new Mock<IHelper>();
    var subject = new Subject(helperMock.Object, 12);

    // Act.
    subject.MainMethod();

    // Assert.
    helperMock.Verify(h => h.KidMethod());
}

重点是你要求的不是你应该做的。是的,mocking 框架可以验证方法调用,on mocks。你模拟依赖关系。

您没有依赖项,您想测试您要测试的 class 上的一个方法调用您要测试的 class 上的另一个方法。

这不是模拟或单元测试的目的,你在这里做错了。在同一个 class 上调用另一个方法的方法是一个实现细节,而不是您应该测试的东西。重要的是方法的输出,或者方法调用后对象的状态。测试 那个.

参见示例 How to use Moq in unit test that calls another method in same class