提供接口的实现以供 Moq 使用

Joh*_*ner 5 c# moq

假设我有以下设置:

public interface IFoo
{
    string DoSomething();
    string DoAnotherThing();
}

public sealed class Bar : IFoo
{
    public string DoAnotherThing() => "DoAnotherThing";
    public string DoSomething() => "DoSomething";
}
Run Code Online (Sandbox Code Playgroud)

使用 Moq,我想模拟 的一种方法Bar,但调用另一种方法的实现。我知道我可以通过创建一个委托给的包装类来做到这一点Bar,如下所示:

public class MockableBar : IFoo
{
    private readonly IFoo _bar;
    public MockableBar(IFoo bar) => _bar = bar;
    public virtual string DoAnotherThing() => _bar.DoAnotherThing();
    public virtual string DoSomething() => _bar.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

然后像这样嘲笑它:

var fake = new Moq.Mock<MockableBar>(new Bar()) { CallBase = true };        
fake.Setup(_ => _.DoSomething()).Returns("Mock");

Assert.AreEqual("DoAnotherThing", fake.Object.DoAnotherThing());
Assert.AreEqual("Mock", fake.Object.DoSomething());
Run Code Online (Sandbox Code Playgroud)

是否有更通用的方法来完成此任务,这样我就不必为我想在此机制中测试的每个接口创建一个新的包装类?

Ade*_*mak 0

我认为你忽略了一些要点。不需要mockablebar。您可以直接模拟IFoo接口。(模拟也适用于虚拟方法和接口)。哪里需要Bar反对,实际上应该使用IFoo对象。当你想测试 bar 类时,你的 sut (被测系统)对象直接是一个 bar 。

\n\n

注意:在测试过程中,如果您必须创建额外的类,这意味着您的代码不可测试。

\n\n

如果你的代码中有这样的用法:

\n\n
public void SomeFunction(Bar bar)\n{\n   .... Do something\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以这样更改(并且由于这一点,您可以模拟参数并轻松编写测试方法)

\n\n
public void SomeFunction(IFoo bar)\n{\n   .... Do something\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

你的测试应该是这样的

\n\n
Mock<IFoo> myMock = new Mock<IFoo>();\n\nmyMock.setup(m=>m.DoSomething()).Returns(()=>\xe2\x80\x9dsome wantted result\xe2\x80\x9d);\n//Or\nmyMock.setup(m=>m.DoSomething()).Throws(()=>new Exception(\xe2\x80\x9csome message\xe2\x80\x9d));\n\nsut = new SomeClass();\nsut.SomeFunction(myMock);\nassert....\n
Run Code Online (Sandbox Code Playgroud)\n