分配给Moq读取的out参数的值。怎么样?

时间:2015-12-15 14:52:54

标签: c# moq

此代码基于此答案:https://stackoverflow.com/a/3135677/360211

public interface IService
{
    void DoSomething(out string a);
}

[Test]
public void Test()
{
    var mock = new Mock<IService>();
    string expectedValue = "value";
    mock.Setup(s => s.DoSomething(out expectedValue));

    string actualValue;
    mock.Object.DoSomething(out actualValue);
    Assert.AreEqual("value", actualValue);
}

就我所知,并且就resharper而言,并不需要赋值string expectedValue = "value";。但是删除它并且Assert失败了!

那么Moq如何从out参数中读取值?

3 个答案:

答案 0 :(得分:1)

重要的一点是:

mock.Setup(s => s.DoSomething(out expectedValue));

此设置意味着,当方法执行时,任何调用DoSomething的方法都会将expectedValue的值放入实际的out变量中。

或许考虑一个更有用的方案,它不是直接测试mock.Object,而是测试一个注入了IService的类。

public class Foo
{
    private IService service;
    public Foo(IService service)
    {
        this.service = service;
    }

    public string GetData()
    {
        string outData;
        service.DoSomething(out outData);

        return outData != "" ? outData : "There was no data";
    }
}

[Test]
public void FooTest_ServiceReturnsEmptyString()
{
    var mock = new Mock<IService>();
    // ReSharper disable once RedundantAssignment
    string expectedValue = "";
    mock.Setup(s => s.DoSomething(out expectedValue));

    var fooObj = new Foo(mock.Object);
    var result = fooObj.GetData();

    Assert.AreEqual("There was no data", result);
}

[Test]
public void FooTest_ServiceReturnsValue()
{
    var mock = new Mock<IService>();
    string expectedValue = "data";
    mock.Setup(s => s.DoSomething(out expectedValue));

    var fooObj = new Foo(mock.Object);
    var result = fooObj.GetData();

    Assert.AreEqual(expectedValue, result);
}

在两个不同的测试中,您可以更改模拟返回的内容,现在您可以根据服务中的不同数据测试您的类的行为。

答案 1 :(得分:0)

out参数不是必需要初始化,但是必须必须在函数返回时分配。

我不知道mock.Object.DoSomething(out actualValue);内部发生了什么,但是使用out参数定义它似乎很奇怪。从您报告的行为来判断,我认为它应该是ref。在将ref参数作为参数传递给函数之前,必须初始化该参数。

答案 2 :(得分:0)

我认为原因是它传递的只是类型Expression<Action<IService>>的表达式并且表达式中的参数被捕获(因此,如果更改了expectedValue的值,表达式中的值也会更改)。值得注意的是,如果使用普通参数而不是out参数,表达式是相同的。

我想可能根本就没有对该参数做任何事情。当您设置方法时,您在Mock对象中放置了一堆元数据,告诉它您已经完成了什么,当您在模拟对象上调用该方法时,它使用该元数据来确定返回的内容或者可能需要的其他内容。做。

值得注意的是,它可能没有调用任何东西,并使用out修饰符传递它的参数,所以结果基本上与你没有那条线一样,那就是Mock甚至没有尝试设置该变量的值。这意味着,基本上你在声明它时设置expectedValue的值,然后没有任何改变它,然后你有一个基于它的断言。

我无法进行任何测试来证明这个理论,而且我对表达式的理解不够自信,或者模仿说这肯定是在发生什么,但是从我看到的代码我认为它至少接近于此。我的不确定性是这样的,我打算将其作为评论发布,但这有点太长了。 ; - )

说完所有这些,即使Mock正在做一些事情,它可以读取你的变量,尽管它是一个out参数是因为它是表达式的一部分。您应该能够通过使用以下代码,设置适当的断点并检查来看到这一点:

string expectedValue = "FNORDFNORD"; 
Expression<Action<IService>> expression = s => s.DoSomething(out expectedValue);