提供Moq使用接口的实现

时间:2018-04-05 21:46:18

标签: c# moq

假设我有以下设置:

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

public sealed class Bar : IFoo
{
    public string DoAnotherThing() => "DoAnotherThing";
    public string DoSomething() => "DoSomething";
}

使用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();
}

然后嘲笑它:

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());

是否有更通用的方法来实现这一点,所以我不必为我想在此机制中测试的每个接口创建一个新的包装类?

2 个答案:

答案 0 :(得分:0)

我想你错过了一些观点。没有必要使用mockablebar。您可以直接模拟IFoo界面。 (Mock也适用于虚方法和接口)。你需要Bar对象在哪里,实际上你应该使用IFoo对象。当你想测试bar类时,你的sut(被测系统)对象就是一个直接的吧。

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

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

public void SomeFunction(Bar bar)
{
   .... Do something
}

你可以这样改变(并且由于这个,你可以模拟参数并轻松编写测试方法)

public void SomeFunction(IFoo bar)
{
   .... Do something
}

你的测试看起来应该是

Mock<IFoo> myMock = new Mock<IFoo>();

myMock.setup(m=>m.DoSomething()).Returns(()=>”some wantted result”);
//Or
myMock.setup(m=>m.DoSomething()).Throws(()=>new Exception(“some message”));

sut = new SomeClass();
sut.SomeFunction(myMock);
assert....

答案 1 :(得分:0)

如果我理解你的问题,你有一个实现IFoo的Bar对象。您正在测试的另一个对象取决于Bar,但您想要将Bar替换为假测试。

如下:

// Arrange
Mock<IFoo> fooMock = new Mock<IFoo>();
fooMock.Setup(s => s.DoSomething()).Returns("Mock");
// using constructor injection, but hook up your IFoo implementer
// to your testObject however you normally would.
MyClass testObject = new MyClass(fooMock.Object);
// Act
testObject.DoSomethingInvokingIFooDoSomething();
// Assert whatever

你的MyClass对象需要使用IFoo而不是Bar来获取它的参数/变量等因为它应该被解耦而不关心它的IFoo提供者如何提供结果,只是它可以。