测试异步方法会产生奇怪的结果

时间:2015-06-21 10:26:20

标签: c# .net nunit

当我正常运行我的测试代码时,NUnit会通知我测试失败了。 result.Contacts的值为3而不是预期的1.当在测试代码中的断言语句上使用断点运行测试代码时,测试不会失败。我怀疑这是一个与多线程有关的问题。

这是我的测试代码

[Test]
public async Task Method_Scenario_IncreasesCount()
{
    // Arrange
    const int employeeId = 1;
    const string managerId = "asdf";

    // Act
    var result = await _uut.Contact(managerId , employeeId);

    // Assert
    Assert.That(result.Contacts, Is.EqualTo(1));
}

这是测试中的代码

public async Task<MyObject> Contact(string managerId, int employeeId)
{
    var today = DateTime.UtcNow.Date;

    var myStoredObject = _myObjectRepository.GetAll().Include(p => p.Employee).First(x => x.Employee.Id == employeeId);

    myStoredObject.Contacts += 1;
    myStoredObject.LastContact = today;

    var dates = new List<DateTime>
    {
        myStoredObject.FirstDate,
        myStoredObject.SecondDate,
        myStoredObject.ThirdDate
    };

    if (!dates.Contains(today))
    {
        await _logging.Log(myStoredObject, Log.Extra);

        await _myObjectRepository.UpdateAsync(myStoredObject);
    }

    return myStoredObject;
}

使用_myObjectRepository模拟_loggingMoq个对象; myStoredObject由我预定义,所以我知道联系人的值是0开始。

为什么测试只在我在assert语句中使用断点时才会通过?我该如何解决这个问题?

修改

我还尝试使用Moq执行此操作:

_mock.Verify(r => r.UpdateAsync(It.Is<MyObject>(m => m.Contacts == 1)));

但是这也失败了,MockException说:

  

模拟上的预期调用至少一次,但从未执行过。

但是,如果我单步执行该程序,我可以看到使用MyObject Contacts = 1来调用此方法。

1 个答案:

答案 0 :(得分:2)

如果没有看到[SetUp]代码,很难说出可能导致问题的原因。我注意到你的测试中的模拟和单元是成员变量 - 可能是共享状态与另一个测试存在问题。我能够编写相同的测试,并且一致地通过

[Test]
public async Task Method_Scenario_IncreasesCount()
{
    // Arrange
    const int employeeId = 55378008;
    var existingEntity = new MyObject {Employee = new Employee {Id = employeeId}};
    var repo = Mock.Of<IMyObjectRepo>(r => r.GetAll() == new[] {existingEntity}.AsQueryable());
    var uut = new MyUut(repo, Mock.Of<ILog>());

    // Act
    var entity = await uut.Contact(string.Empty, employeeId);

    // Assert
    Assert.That(entity.Contacts, Is.EqualTo(1));
    Mock.Get(repo).Verify(r => r.UpdateAsync(entity));
}