如何在模拟 class 方法的 `Setup`/`Verify` 中使用 `out` 参数?
How to work with `out` parameters in `Setup`/`Verify` for mocked class methods?
public class MyClass
{
public virtual void Method1(string par1, int par2)
{
// ...
var result = new Dictionary<byte, string>();
for(var i = 0; i < 100; i++)
{
if(someCondition) break;
Method2(par1, out byte res1, out string res2);
result[res1] = res2;
}
// ...
}
public virtual void Method2(string par1, out byte res1, out string res2)
{
// ...
res1 = 1;
res2 = "res2";
// ...
}
}
// test class
public class MyClassTests
{
[Fact]
public void TestMethod()
{
string par1 = "value";
int par2 = 2;
var myClassMock = new Mock<MyClass>() { CallBase = true };
myClassMock.Verify(v => v.Method1(par1, par2), Times.Once);
myClassMock.Verify(v => v.Method2(It.IsAny<string>(), out ?, out ?), Times.AtMost(3));
}
}
根据某些条件,Method2
的调用次数不应超过 3 次。测试正在检查,该逻辑是否按具体查询的预期工作。
问题是:没有人能确切地知道应该返回哪些值。此外,它可能是一个非常大的集合。我想,It.IsAny<>()
在这里应该是正确的位置,但它不适用于 out
参数。
这种情况有什么办法吗?
我通过内联 ref
-匹配解决了这个问题。
myClassMock
.Verify(v =>
v.Method2(It.IsAny<string>(), out It.Ref<byte>.IsAny, out It.Ref<string>.IsAny,),
Times.AtMost(3));
像我 on 一样,不要在 Moq 不会执行任何匹配的地方使用 It.*
匹配器;因为如果这样做,阅读您代码的人可能很容易被误导,以为 Moq 会执行某种参数匹配(事实并非如此,匹配器仅适用于输入参数)。
使用 It.Ref<T>.IsAny
仍然有效,因为它只不过是类型 T
的静态字段。但是您也可以使用适当类型的任何其他字段或变量。这样做——使用另一个变量——是我的建议,以防止上述问题(误导性代码)。
// declare some dummy variables; the names don't matter.
byte _;
string __;
// then use & forget about them.
myClassMock.Verify(v => v.Method2(It.IsAny<string>(), out _, out __), Times.AtMost(3));
// ^^^^^ ^^^^^^
public class MyClass
{
public virtual void Method1(string par1, int par2)
{
// ...
var result = new Dictionary<byte, string>();
for(var i = 0; i < 100; i++)
{
if(someCondition) break;
Method2(par1, out byte res1, out string res2);
result[res1] = res2;
}
// ...
}
public virtual void Method2(string par1, out byte res1, out string res2)
{
// ...
res1 = 1;
res2 = "res2";
// ...
}
}
// test class
public class MyClassTests
{
[Fact]
public void TestMethod()
{
string par1 = "value";
int par2 = 2;
var myClassMock = new Mock<MyClass>() { CallBase = true };
myClassMock.Verify(v => v.Method1(par1, par2), Times.Once);
myClassMock.Verify(v => v.Method2(It.IsAny<string>(), out ?, out ?), Times.AtMost(3));
}
}
根据某些条件,Method2
的调用次数不应超过 3 次。测试正在检查,该逻辑是否按具体查询的预期工作。
问题是:没有人能确切地知道应该返回哪些值。此外,它可能是一个非常大的集合。我想,It.IsAny<>()
在这里应该是正确的位置,但它不适用于 out
参数。
这种情况有什么办法吗?
我通过内联 ref
-匹配解决了这个问题。
myClassMock
.Verify(v =>
v.Method2(It.IsAny<string>(), out It.Ref<byte>.IsAny, out It.Ref<string>.IsAny,),
Times.AtMost(3));
像我 It.*
匹配器;因为如果这样做,阅读您代码的人可能很容易被误导,以为 Moq 会执行某种参数匹配(事实并非如此,匹配器仅适用于输入参数)。
使用 It.Ref<T>.IsAny
仍然有效,因为它只不过是类型 T
的静态字段。但是您也可以使用适当类型的任何其他字段或变量。这样做——使用另一个变量——是我的建议,以防止上述问题(误导性代码)。
// declare some dummy variables; the names don't matter.
byte _;
string __;
// then use & forget about them.
myClassMock.Verify(v => v.Method2(It.IsAny<string>(), out _, out __), Times.AtMost(3));
// ^^^^^ ^^^^^^