假设我有以下设置:
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());
是否有更通用的方法来实现这一点,所以我不必为我想在此机制中测试的每个接口创建一个新的包装类?
答案 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提供者如何提供结果,只是它可以。