使用 Moq 时,是否应该执行模拟接口实现的方法?

When using Moq, are mocked interfaces implemented methods supposed to execute?

我刚开始使用 Moq,大约 5 年没有进行单元测试了。很多事情都变了。

我正在努力了解基础知识。

我有一个接口。

public interface ILogger
{
    void Log(string message)
}

而这个接口的实现方式如下

public class MyLogger : ILogger
{
    public virtual void Log(string message)
    {
        StaticClass.StaticMethodNotToBeCalled<ILogger>().Log(message);
    }
}

我正在测试以下逻辑。

public class MyClass
{
    public MyMethod(int z)
    {
        var logger = new MyLogger();

        if(z == 5) 
        {
           logger.Log("it is true");

           return true;
        }

        logger.Log("it is false);

        return false;
    }
}

我的测试如下所示。

[TestMethod]
public void Test_MyMethod()
{
    var mock = new Mock<ILogger>();

    mock.Setup(y => y.Log(It.IsAny<string>()).Verifiable();

    var o = new MyClass();

    var result = o.MyMethod(5);

    Assert.IsTrue(result);        

    mock.Verify();

}

我 运行 遇到的问题是在 ILogger 接口的实现中调用的静态方法。

我猜我只是不太了解 mock 到底应该做什么。

我想做的是任何时候 ILogger.Log 它被覆盖并且不调用该静态方法。

这可能吗?

我是不是做错了?

您正在创建一个基于 ILogger 接口的 Mock,但您没有将 Mock 注入到您的 MyClass 实例中。当 MyClass 执行时,它使用 Logger 的实例而不是你的 ILogger 模拟。

为您的 class 考虑这样的事情:

public class MyClass
{

    private ILogger logger;
    public MyClass(ILogger loggerInstance)
    {
        logger=loggerInstance;
    }
    public MyMethod(int z)
    {

        if(z == 5) 
        {
           logger.Log("it is true");

           return true;
        }

        logger.Log("it is false);

        return false;
    }
}

请注意,在 MyClass 的构造函数中,您现在正在接受实现 ILogger 接口的 class 实例。这允许您注入模拟对象来代替实际的具体记录器:

[TestMethod]
public void Test_MyMethod()
{
    var mock = new Mock<ILogger>();

    mock.Setup(y => y.Log(It.IsAny<string>()).Verifiable();

    var o = new MyClass(mock.Object);

    var result = o.MyMethod(5);

    Assert.IsTrue(result);        

    mock.Verify();

}

依赖注入 是您在场景中缺少的概念。在许多情况下,编写可单元测试的代码是必不可少的。