单元测试。为什么Mock在第二个循环迭代中返回不同的值?

时间:2019-03-06 08:57:27

标签: c# unit-testing mocking moq

我对以下对象进行模拟,其目的是收集传感器数据。它实现了以下接口:

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);
}

问题:this.AdwSensorDataCollector.CollectSensorData(10);行的第二次迭代返回一个空列表。但是我希望它每次都返回我在设置中指定的值:

collector.Setup((x) => x.CollectSensorData(10)
         .Returns(new List<int> { 1,2,3,4,5,6,7,8,9});

我想这与values.Clear();有关,因为如果我删除列表清除。 CollectSensorDataRepeatIfFails的返回值在所有迭代中均保持不变,并且我的问题消失了。但这只是一个猜测。我真的很想知道为什么第二个调用不返回指定的返回值。

问题:我想念什么?该设置仅适用于1次调用模拟方法吗?还是有一个我忘记按下以使其表现出预期效果的按钮?为什么清除列表会影响模拟方法的第二次调用的返回值?有人可以阐明这件事吗?

在询问之前,我做了一些研究,但是我只能找到说明如何使模拟在下一次调用时返回不同值的帖子。但是没有使用循环出现问题的帖子。对于重复的提示我也很高兴。

欢呼

2 个答案:

答案 0 :(得分:4)

  

我想念什么?该设置仅适用于1次调用模拟方法吗?

实际上,这是模拟的预期行为。该设置是可变的,因为您可以更改捕获的参数或通过引用返回值。您正在通过values.Clear();进行此操作。为避免此问题,只需通过提供工厂来延迟列表的创建。像这样:

collector.Setup((x) => x.CollectSensorData(10))
    .Returns<int>((i) => new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 });

答案 1 :(得分:4)

这是预期的行为,因为您正在使用该列表的引用。无论您从模拟还是其他地方退回它。

collector.Setup((x) => x.CollectSensorData(10)
    .Returns(new List<int> { 1,2,3,4,5,6,7,8,9});

您正在向<{1}注册参考

List<int>

因此,在此呼叫中,您收到对完全相同 List<int> values = this.AdwSensorDataCollector.CollectSensorData(10);对象的引用。

List<int>

调用此操作将删除模拟应返回的相同列表中的所有项目。

您可以在此处阅读有关参考类型的更多信息: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/reference-types

更新: 您可以使用values.Clear()代替.Callback(() => new List<int>() { 1, 2, 3})。在这种情况下,每次调用模拟函数时都会调用回调。