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

Testing async method produces weird result

当我运行我的测试代码正常时,NUnit 通知我测试失败。 result.Contacts 的值为 3 而不是预期的 1。当测试代码为 运行 并且在测试代码中的 assert 语句上设置断点时,测试不会失败。我怀疑这是与多线程相关的问题。

这是我的测试代码

[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_logging 对象使用 Moq 模拟; myStoredObject 是我预定义的,所以我知道 Contacts 的值是 0。

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


编辑

我也试过使用 Moq 来做到这一点:

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

但这也失败了,MockException 说:

Expected invocation on the mock at least once, but was never performed.

但是,如果我单步执行程序,我可以看到调用此方法的 MyObject 具有 Contacts = 1.

如果没有看到您的 [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));
}