C# 提供一个接口的实现供Moq使用
假设我有以下设置:C# 提供一个接口的实现供Moq使用,c#,moq,C#,Moq,假设我有以下设置: public interface IFoo { string DoSomething(); string DoAnotherThing(); } public sealed class Bar : IFoo { public string DoAnotherThing() => "DoAnotherThing"; public string DoSomething() => "DoSomething"; } 使用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());
var fake=new Moq.Mock(new Bar()){CallBase=true};
fake.Setup(=>u.DoSomething())。返回(“Mock”);
AreEqual(“DoAnotherThing”,false.Object.DoAnotherThing());
AreEqual(“Mock”,false.Object.DoSomething());
有没有更通用的方法来实现这一点,这样我就不必为我想在这种机制中测试的每个接口都创建一个新的包装类了?我认为您遗漏了一些要点。没有必要使用mockablebar。您可以直接模拟
IFoo
界面。(模拟也适用于虚拟方法和接口)。你需要在哪里设置Bar
object,实际上你应该使用IFoo
object。当您想要测试bar类时,sut(测试中的系统)对象直接是一个bar
注意:在测试期间,如果您必须创建额外的类,这意味着您的代码是不可测试的
如果代码中有类似的用法:
public void SomeFunction(Bar bar)
{
.... Do something
}
您可以这样更改(由于这样,您可以模拟参数并轻松编写测试fot方法)
你的测试应该是
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....
Mock myMock=new Mock();
myMock.setup(m=>m.DoSomething())。返回(()=>“一些想要的结果”);
//或
myMock.setup(m=>m.DoSomething()).Throws(()=>newexception(“somemessage”);
sut=新的SomeClass();
sut.SomeFunction(myMock);
断言。。。。
如果我正确理解了您的问题,您有一个实现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
//排列
Mock fooMock=新Mock();
Setup(s=>s.DoSomething())。返回(“Mock”);
//使用构造函数注入,但连接IFoo实现者
//以通常的方式添加到testObject。
MyClass testObject=新的MyClass(fooMock.Object);
//表演
testObject.dosomethinginovokinifoodosomething();
//断言
MyClass对象的参数/变量等需要使用IFoo而不是Bar,因为它应该是解耦的,并且不关心其IFoo提供程序如何得出结果,只要它可以。我想模拟
Bar
的一部分,但对其他调用使用基本实现,因此创建了MockableBar
。这些不是单元测试,而是更多的子系统集成测试,我想验证Bar.DoAnotherThing()
is在子系统处于特定状态时是否返回正确的值。我正在寻找一种通用方法来解决此问题,因此,我不必每次调用接口的实现时都创建mockable类。我希望有一种方法可以创建一个像包装器那样的东西,它使用T
,我可以在任何地方使用这个模式。我更新了示例,让mockable类使用IFoo
,以使其更清晰一些。我不清楚您的要求。您正在测试的每件事情都有关于如何设置模拟的特定要求,这排除了通用解决方案。但是,如果您有许多测试用例共享90%的设置,那么您可以创建一个helper CreateDefaultIFooMock()方法,然后每个测试都可以向其中添加特定于测试用例的设置。(我使用IConfig接口完成了这项工作,您可能在给定的测试中测试特定的配置属性,但在其他情况下,每个属性都需要合理的默认值)。我希望默认行为是调用Bar
的实现,但我希望能够覆盖该行为。我通过创建MockableBar
实现了这一点。假设我还有10个接口有类似的需求,我不希望创建多个类,所有这些类都委托给这些接口的实现。我希望有一种方法可以创建一个在默认情况下调用实现的mock,并且我可以在事后重写我需要的东西?你能不能对条码进行部分模拟,并获得相同的结果?为什么条码是密封的?这似乎就是问题所在。Bar是密封的,因为该类不是为继承而设计的。解封Bar将使您的生活更加简单。如果在运行时自动生成代理类(模拟您的MockableBar
),会怎么样?虽然我同意Michael的观点,但无缘无故地封闭课堂常常会带来很多痛苦(不是对你,而是对你图书馆的用户)。我曾多次击中,我需要从第三方库中继承以实现我的目标的类被密封,尽管我从未想过“我希望该类被密封,如果我不能从中继承,那将对我非常有益”。然而,这当然是基于观点的。
// 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