单元测试。为什么在第二次循环迭代中模拟 returns 不同的值?
Unit test. Why Mock returns different value in second loop iteration?
我在以下对象上有一个 Mock,其工作是收集传感器数据。它实现了这个接口:
public interface ISensorDataCollector
{
List<int> CollectSensorData(int amountOfValues);
}
测试里面我有如下安排:
// ARRANGE
var collector = new Mock<ISensorDataCollector>() { CallBase = true };
// Mock SensorDataCollector
collector.Setup((x) => x.CollectSensorData(10)
.Returns(new List<int> { 1,2,3,4,5,6,7,8,9});
myProcess.AdwSensorDataCollector = collector.Object;
// ACT
myProcess.CollectSensorDataRepeatIfFails(5);
要测试的方法有一个用于收集数据的 while 循环。简单版本如下所示:
public ISensorDataCollector SensorDataCollector { get; set; }
public void CollectSensorDataRepeatIfFails(int counterForRepeatedMeasurement)
{
do
{
List<int> values = this.SensorDataCollector.CollectSensorData(10);
values.Clear();
counterForRepeatedMeasurement--;
} while (counterForRepeatedMeasurement >= 0);
}
问题:从第 2 次迭代开始,第 this.AdwSensorDataCollector.CollectSensorData(10);
return 行是一个空列表。但我希望它 return 我每次在设置中指定的值:
collector.Setup((x) => x.CollectSensorData(10)
.Returns(new List<int> { 1,2,3,4,5,6,7,8,9});
我猜这与values.Clear();
有关,因为如果我删除列表清除。 CollectSensorDataRepeatIfFails
的 return 值在所有迭代中保持不变,我的问题就消失了。但这只是一个猜测。我真的很想知道为什么第二次调用没有return指定return值。
问题:我错过了什么?该设置是否仅适用于模拟方法的 1 次调用?或者是否有一个按钮我忘记按下以使其按预期方式运行?为什么清空列表会影响第二次调用 mocked 方法的 return 值?有人可以解释一下这个问题吗?
我在询问之前做了一些研究,但我只能找到 post 解释如何在下次调用时将模拟设为 return 不同值的内容。但是没有post问题出现的地方使用循环。我也很高兴重复提示。
干杯
What did I miss? Does the setup work only for 1 invocation of the mocked method?
实际上这是模拟的预期行为。该设置是可变的,因为您可以通过引用更改捕获的参数或 return 值。 values.Clear();
你正是这样做的。为避免此问题,只需通过提供工厂来推迟列表的创建。像这样:
collector.Setup((x) => x.CollectSensorData(10))
.Returns<int>((i) => new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
这是预期的行为,因为您正在使用该列表的引用。无论你 return 它来自 mock,还是其他地方。
collector.Setup((x) => x.CollectSensorData(10)
.Returns(new List<int> { 1,2,3,4,5,6,7,8,9});
您正在将 reference 注册到 List<int>
。
List<int> values = this.AdwSensorDataCollector.CollectSensorData(10);
因此,在此调用中,您接收到对 完全相同 List<int>
对象的引用。
values.Clear()
调用此方法会删除 mock 应该 return.
的 相同列表 的所有项目
您可以在此处阅读有关引用类型的更多信息:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types
更新:
您可以使用 .Callback(() => new List<int>() { 1, 2, 3})
而不是 Returns
。在这种情况下,每次调用模拟函数时都会调用回调。
我在以下对象上有一个 Mock,其工作是收集传感器数据。它实现了这个接口:
public interface ISensorDataCollector
{
List<int> CollectSensorData(int amountOfValues);
}
测试里面我有如下安排:
// ARRANGE
var collector = new Mock<ISensorDataCollector>() { CallBase = true };
// Mock SensorDataCollector
collector.Setup((x) => x.CollectSensorData(10)
.Returns(new List<int> { 1,2,3,4,5,6,7,8,9});
myProcess.AdwSensorDataCollector = collector.Object;
// ACT
myProcess.CollectSensorDataRepeatIfFails(5);
要测试的方法有一个用于收集数据的 while 循环。简单版本如下所示:
public ISensorDataCollector SensorDataCollector { get; set; }
public void CollectSensorDataRepeatIfFails(int counterForRepeatedMeasurement)
{
do
{
List<int> values = this.SensorDataCollector.CollectSensorData(10);
values.Clear();
counterForRepeatedMeasurement--;
} while (counterForRepeatedMeasurement >= 0);
}
问题:从第 2 次迭代开始,第 this.AdwSensorDataCollector.CollectSensorData(10);
return 行是一个空列表。但我希望它 return 我每次在设置中指定的值:
collector.Setup((x) => x.CollectSensorData(10)
.Returns(new List<int> { 1,2,3,4,5,6,7,8,9});
我猜这与values.Clear();
有关,因为如果我删除列表清除。 CollectSensorDataRepeatIfFails
的 return 值在所有迭代中保持不变,我的问题就消失了。但这只是一个猜测。我真的很想知道为什么第二次调用没有return指定return值。
问题:我错过了什么?该设置是否仅适用于模拟方法的 1 次调用?或者是否有一个按钮我忘记按下以使其按预期方式运行?为什么清空列表会影响第二次调用 mocked 方法的 return 值?有人可以解释一下这个问题吗?
我在询问之前做了一些研究,但我只能找到 post 解释如何在下次调用时将模拟设为 return 不同值的内容。但是没有post问题出现的地方使用循环。我也很高兴重复提示。
干杯
What did I miss? Does the setup work only for 1 invocation of the mocked method?
实际上这是模拟的预期行为。该设置是可变的,因为您可以通过引用更改捕获的参数或 return 值。 values.Clear();
你正是这样做的。为避免此问题,只需通过提供工厂来推迟列表的创建。像这样:
collector.Setup((x) => x.CollectSensorData(10))
.Returns<int>((i) => new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
这是预期的行为,因为您正在使用该列表的引用。无论你 return 它来自 mock,还是其他地方。
collector.Setup((x) => x.CollectSensorData(10)
.Returns(new List<int> { 1,2,3,4,5,6,7,8,9});
您正在将 reference 注册到 List<int>
。
List<int> values = this.AdwSensorDataCollector.CollectSensorData(10);
因此,在此调用中,您接收到对 完全相同 List<int>
对象的引用。
values.Clear()
调用此方法会删除 mock 应该 return.
的 相同列表 的所有项目您可以在此处阅读有关引用类型的更多信息: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types
更新:
您可以使用 .Callback(() => new List<int>() { 1, 2, 3})
而不是 Returns
。在这种情况下,每次调用模拟函数时都会调用回调。