【问题标题】:Mock in unit test returns null at LINQ.Where单元测试中的模拟在 LINQ.Where 处返回 null
【发布时间】:2018-09-12 11:11:39
【问题描述】:

我有两个类BeamTreatment,我想匹配它们的值DateTime TimeStamp。因此,在我的代码中,我有一个 LINQ .Where() 来搜索特殊的时间戳并将其与预先排序的列表进行比较。使用真实数据它工作得非常好并且没有任何错误,但是现在我被告知要为这个类编写一个单元测试并且使用Moq 我没有得到预期的结果。

我的代码中不起作用的那一行是:

Treatment searchedBeam = (Treatment)InputData.Treatments.
    Where(beam => beam.TimeStamp == sortingList[j + i * rangeOfBeams]).FirstOrDefault();

i,j 是来自 for 循环的索引,并且正如我在调试模式下看到的那样正确运行。

在我的单元测试代码中,我有这个:

Mock<ITreatmentGroup> treatGroupMock1;
[SetUp]
public override void Init()
{
    base.Init();

    // --- Create Plan Mock
    // some code here

    // --- Create Treatment Mock
    DateTime time1 = new DateTime(2000, 01, 01, 12, 00, 00);
    DateTime time2 = new DateTime(2000, 01, 01, 13, 00, 00);

    Mock<ITreatment> treatMock1 = new Mock<ITreatment>();
    treatMock1.Setup(t => t.TimeStamp).Returns(time1);
    Mock<ITreatment> treatMock2 = new Mock<ITreatment>();
    treatMock2.Setup(t => t.TimeStamp).Returns(time2);

    treatGroupMock1 = new Mock<ITreatmentGroup>();
    treatGroupMock1.Setup(tg => tg.Treatments).Returns(new List<ITreatment>() { treatMock1.Object, treatMock2.Object });
}

在调试中,我检查了模拟数据与真实数据的结构是否相同。但是接下来是我的测试代码:

[Test]
public void Matched_MatchedAndSortedPlan_FunctionCheck()
{
    IPlan result = Matched.MatchedAndSortedPlan(_planMock.Object, _treatGroupMock1.Object, out IList<string> errors);

    Assert.IsEmpty(errors);
    Assert.IsNotNull(result);
    Assert.IsTrue(result.FractionGroups[0].Beams.Any(f => f.BeamName == "beamMock1"));              
}

所以我使用模拟数据调用我的方法,并且与真实数据一样,它应该可以工作,但正如我提到的带有 LINQ 表达式的行返回 null 所以 Assert 命令让单元测试失败。

我得到的最大提示是模拟 LINQ 表达式存在一些问题,但我不想模拟 LINQ 表达式,而是将它用于我的解决方案。此处的其他问题,例如 thisthis,Google 向我展示了我的搜索结果,我认为在这里不起作用。

希望你对我有其他的线索或提示。

【问题讨论】:

  • Matched 也是 Mock 还是真实对象? _planMock 是什么?它在哪里定义?首先,我将验证对我为其创建设置的方法的调用实际上已完成,例如:treatGroupMock1.Verify(...)
  • Matched 是我要测试的真实类。有人告诉我,为了进行良好的代码开发,我应该在更改课程之前编写一个单元测试。所以_planMockTreatment 的对面站点,其中提到的Beam 存储在列表中。但我会尝试你的建议使用.Verify()

标签: c# linq unit-testing mocking moq


【解决方案1】:

Linq Where 工作正常。 searchedBeam 被分配 null 因为试图从模拟接口转换为具体类型。

                          right here
                              |
                              v
Treatment searchedBeam = (Treatment)InputData.Treatments.
    Where(beam => beam.TimeStamp == sortingList[j + i * rangeOfBeams]).FirstOrDefault();

您将返回的结果转换为Treatment,而在测试集合中设置的项目只是ITreatment 的模拟。

如果您能够创建Treatment 的实际实例而没有副作用,那么创建并使用它们进行测试

[SetUp]
public override void Init() {
    base.Init();

    // --- Create Plan Mock
    // some code here

    // --- Create Treatment Mock
    DateTime time1 = new DateTime(2000, 01, 01, 12, 00, 00);
    DateTime time2 = new DateTime(2000, 01, 01, 13, 00, 00);

    var treatMock1 = new Treatment {
        TimeStamp = time1
    };
    var treatMock2 = new Treatment {
        TimeStamp = time2
    };

    treatGroupMock1 = new Mock<ITreatmentGroup>();
    treatGroupMock1.Setup(_ => _.Treatments).Returns(new List<ITreatment>() { treatMock1, treatMock2 });
}

这样,在进行测试时,演员表的行为就符合预期。

【讨论】:

  • 这很好,但也许你允许我问一个问题。通过这种方式创建结构,是否有必要再使用Moq
  • 在这种特殊情况下的测试需要最小起订量和实际实例的组合。如果它们的实例在测试时会引起问题,则可以模拟具有副作用的依赖项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
  • 2021-08-02
  • 2020-11-02
  • 2020-05-09
相关资源
最近更新 更多