C# 基于对同一模拟对象的早期void方法调用定义模拟响应
这是我想要模拟的类,它被大量截断C# 基于对同一模拟对象的早期void方法调用定义模拟响应,c#,moq,C#,Moq,这是我想要模拟的类,它被大量截断 public class FooHandler { private FooInstance foo; public void ConstructInstance(string fooSpecs) { foo = SomeMethod(fooSpecs); } public string GetSomeProperty() { return foo.SomeProperty();
public class FooHandler
{
private FooInstance foo;
public void ConstructInstance(string fooSpecs)
{
foo = SomeMethod(fooSpecs);
}
public string GetSomeProperty()
{
return foo.SomeProperty();
}
}
实际上,每种方法都有很多内在逻辑。这就是我的想法
我要测试的代码需要一个foodhandler,它一个接一个地调用这两个方法
我想模拟foodhandler来测试代码是否正确调用它
var mockedFooHandler = new Mock<FooHandler>();
mockedFooHandler.Setup(x => x.ConstructInstance(EXAMPLE_FOO_SPEC));
mockedFooHandler.Setup(x => x.GetSomeProperty()).Returns(EXPECTED_PROPERTY);
var mockedFooHandler=new Mock();
Setup(x=>x.ConstructInstance(示例_FOO_SPEC));
Setup(x=>x.GetSomeProperty())。返回(预期的_属性);
现在,我想把这两种设置结合起来。如果使用不同的示例\u FOO\u规范调用了第一个方法,我希望返回不同的预期\u属性。第一个方法为void,第二个方法不带参数。所以我想设置模拟对象的内部状态,就像真实对象那样。但国家是私人的
制作几个不同的MockedFoodHandler,使用它们自己的编程响应,在不同的位置注入,是不可能的
我应该怎么做呢?对于void方法,可以使用
验证
来验证是否以某种方式调用了方法。例如:
\u mockedInstance.Verify(x=>x.Method(expectedParameter),Times.Once)代码>
如果未按预期调用该方法,则验证将引发异常,从而导致测试失败。这应该在测试结束时调用,您通常会在测试结束时断言结果
如果我理解正确,您希望您的模拟能够根据前一个方法从被测类接收到的内容,从一个方法返回值
下面通过捕获传递给第一个模拟方法的参数,并使用该捕获的参数作为第二个模拟方法的Returns方法中lambda函数的输入来实现这一点
public class UnitTest1
{
[TestMethod]
public void Can_Capture_Parameters()
{
var mockedFooHandler = new Mock<IFooHandler>();
string response = "";
// Here we use the moq Callback function to capture the paramter
mockedFooHandler.Setup(x => x.ConstructInstance(It.IsAny<string>()))
.Callback<string>(r => response = r);
mockedFooHandler.Setup(x => x.GetSomeProperty()).Returns("b");
mockedFooHandler.Object.ConstructInstance("testing");
Assert.AreEqual("testing", response);
}
[TestMethod]
public void Can_React_To_Parameters()
{
var mockedFooHandler = new Mock<IFooHandler>();
string response = "";
var responseDictionary = new Dictionary<string, string>()
{
{"first", "first response"},
{"second", "second response"},
{"third", "third response"}
};
mockedFooHandler.Setup(x => x.ConstructInstance(It.IsAny<string>()))
.Callback<string>(r => response = r);
// And here we use that captured parameter in a lambda. In this case using a dictionary to determine the desired response
mockedFooHandler.Setup(x => x.GetSomeProperty()).Returns(() => responseDictionary[response]);
mockedFooHandler.Object.ConstructInstance("first");
Assert.AreEqual("first response", mockedFooHandler.Object.GetSomeProperty());
}
}
public interface IFooHandler
{
void ConstructInstance(string fooSpecs);
string GetSomeProperty();
}
public class FooHandler : IFooHandler
{
public void ConstructInstance(string fooSpecs)
{
}
public string GetSomeProperty()
{
return "unexpected data";
}
}
公共类UnitTest1
{
[测试方法]
public void可以捕获参数()
{
var mockedFooHandler=new Mock();
字符串响应=”;
//这里我们使用moq回调函数来捕获参数
mockedFooHandler.Setup(x=>x.ConstructInstance(It.IsAny()))
.回调(r=>response=r);
Setup(x=>x.GetSomeProperty())。返回(“b”);
mockedFoodHandler.Object.ConstructInstance(“测试”);
断言.AreEqual(“测试”,响应);
}
[测试方法]
public void可以对参数()作出反应
{
var mockedFooHandler=new Mock();
字符串响应=”;
var responseDictionary=新字典()
{
{“第一”,“第一反应”},
{“第二个”,“第二个响应”},
{“第三个”,“第三个响应”}
};
mockedFooHandler.Setup(x=>x.ConstructInstance(It.IsAny()))
.回调(r=>response=r);
//这里我们在lambda中使用捕获的参数。在本例中,使用字典来确定所需的响应
Setup(x=>x.GetSomeProperty())。返回(()=>ResponsedEditionary[response]);
mockedFoodHandler.Object.ConstructInstance(“第一”);
AreEqual(“第一个响应”,mockedFoodHandler.Object.GetSomeProperty());
}
}
公共接口IFooHandler
{
void ConstructInstance(字符串fooSpecs);
字符串GetSomeProperty();
}
公共类foodhandler:IFooHandler
{
公共void ConstructInstance(字符串fooSpecs)
{
}
公共字符串GetSomeProperty()
{
返回“意外数据”;
}
}
然而,我同意Kieran Devlin的评论,即这样做的必要性几乎肯定是一种代码气味,并指出您的设计存在一些问题。您能再解释一下您试图实现的目标吗?模拟对象没有可设置的“内部状态”。模拟对象只是一个接口的实现,您可以完全控制它。通常情况下,你会设置你的模拟,为每一对规范和预期编写不同的测试。。。复杂。因此,FooHandler基于规范构造了一个类似statemachine的结构实例,GetSomeProperty使其按照特定规则进行,然后返回结果。我的代码将针对不同的状态机重复执行此操作—每次都重用相同的FooHandler。为了使我的代码按预期运行(允许我测试它是否能够很好地执行辅助功能),我想一次性模拟FooHandler的完整预期行为。让我们看看是否有:)如果状态是私有的,那么您正在测试的类不需要关心它的调用,因为该方法应该有自己的单元测试。如果是这样的话,那么您编写的代码就不能正确地遵循SOLID,因此如果不是这样的话,就很难进行测试。可能您需要重构。如果您的类是紧密耦合的,那么单元测试必须覆盖它所耦合的所有内容,否则它只是部分单元测试。