此代码基于此答案: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
参数中读取值?
答案 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);