Mock 上的设置未返回预期值
Setup on Mock not returning expected value
这是我遇到的一个问题的简化版本:
public interface IService
{
IProvider Provider { get; }
}
public interface IProvider
{
List<int> Numbers{ get; }
string Text { get; }
}
[TestMethod]
public void ServiceTest()
{
var service = new Mock<IService>();
var provider = new Mock<IProvider>();
service.Setup(s => s.Provider).Returns(provider.Object); // A
service.Setup(s => s.Provider.Text).Returns("some text"); // B - incorrect
// they actually meant to do this, instead of 'B'
// provider.Setup(p => p.Text).Returns("some text");
provider.Setup(p => p.Numbers).Returns(new List<int> { 1, 2, 3 });
DummyApplicationCode(service.Object);
}
int DummyApplicationCode(IService service)
{
// will throw, because the Provider was replaced at 'B'
int shouldBeOne = service.Provider.Numbers.First();
return shouldBeOne;
}
单元测试失败,因为在被测应用程序代码中,模拟的 IService
return 错误 IProvider
。
我最终发现了导致它的行(请记住,我正在查看的代码并不像上面那样简单),上面标记为 'B',这是其他人由于误解最小起订量设置而添加的。
我知道模拟中的后续设置会覆盖之前的设置,但我没有发现这个问题,因为违规行的 Return 是为了单独分属性.
我希望这是设计使然,但它让我震惊,因为我没有预料到有人会这样做。
我的问题:因为 'B' 的设置只与提供商 Text[=30= 的 return 有关],为什么服务 'Provider' 属性 需要替换在 'A' 中定义的服务?
查看源代码时,这显然是故意的:
https://github.com/moq/moq4/blob/master/Source/Mock.cs
https://github.com/moq/moq4/blob/master/Source/Interceptor.cs
Setup
通过在 Interceptor
上使用 AddCall
创建 "call"。这包含以下代码块,只要我们创建非条件设置,它就会删除所有以前的设置。甚至评论。
if (!call.IsConditional)
{
lock (calls)
{
// if it's not a conditional call, we do
// all the override setups.
// TODO maybe add the conditionals to other
// record like calls to be user friendly and display
// somethig like: non of this calls were performed.
if (calls.ContainsKey(key))
{
// Remove previous from ordered calls
InterceptionContext.RemoveOrderedCall(calls[key]);
}
calls[key] = call;
}
这是我遇到的一个问题的简化版本:
public interface IService
{
IProvider Provider { get; }
}
public interface IProvider
{
List<int> Numbers{ get; }
string Text { get; }
}
[TestMethod]
public void ServiceTest()
{
var service = new Mock<IService>();
var provider = new Mock<IProvider>();
service.Setup(s => s.Provider).Returns(provider.Object); // A
service.Setup(s => s.Provider.Text).Returns("some text"); // B - incorrect
// they actually meant to do this, instead of 'B'
// provider.Setup(p => p.Text).Returns("some text");
provider.Setup(p => p.Numbers).Returns(new List<int> { 1, 2, 3 });
DummyApplicationCode(service.Object);
}
int DummyApplicationCode(IService service)
{
// will throw, because the Provider was replaced at 'B'
int shouldBeOne = service.Provider.Numbers.First();
return shouldBeOne;
}
单元测试失败,因为在被测应用程序代码中,模拟的 IService
return 错误 IProvider
。
我最终发现了导致它的行(请记住,我正在查看的代码并不像上面那样简单),上面标记为 'B',这是其他人由于误解最小起订量设置而添加的。
我知道模拟中的后续设置会覆盖之前的设置,但我没有发现这个问题,因为违规行的 Return 是为了单独分属性.
我希望这是设计使然,但它让我震惊,因为我没有预料到有人会这样做。
我的问题:因为 'B' 的设置只与提供商 Text[=30= 的 return 有关],为什么服务 'Provider' 属性 需要替换在 'A' 中定义的服务?
查看源代码时,这显然是故意的:
https://github.com/moq/moq4/blob/master/Source/Mock.cs
https://github.com/moq/moq4/blob/master/Source/Interceptor.cs
Setup
通过在 Interceptor
上使用 AddCall
创建 "call"。这包含以下代码块,只要我们创建非条件设置,它就会删除所有以前的设置。甚至评论。
if (!call.IsConditional)
{
lock (calls)
{
// if it's not a conditional call, we do
// all the override setups.
// TODO maybe add the conditionals to other
// record like calls to be user friendly and display
// somethig like: non of this calls were performed.
if (calls.ContainsKey(key))
{
// Remove previous from ordered calls
InterceptionContext.RemoveOrderedCall(calls[key]);
}
calls[key] = call;
}