Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于对同一模拟对象的早期void方法调用定义模拟响应_C#_Moq - Fatal编程技术网

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,因此如果不是这样的话,就很难进行测试。可能您需要重构。如果您的类是紧密耦合的,那么单元测试必须覆盖它所耦合的所有内容,否则它只是部分单元测试。