transporter_room_3
transporter_room_3

Reputation: 2633

Testing async method produces weird result

When I run my test code normally, NUnit informs me that the test has failed. The value of result.Contacts is 3 instead of the expected 1. When the testcode is run with a breakpoint on the assert statement in the test code, the test does not fail. I suspect this is a problem related to multithreading.

This is my test code

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

This is the code under test

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

The _myObjectRepository and _logging objects are mocked using Moq; and the myStoredObject is predefined by me, so I know the value of Contacts is 0 to begin with.

Why does the test only pass when I use a breakpoint on the assert statement? And how do I resolve this issue?


Edit

I've also tried using Moq to do this:

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

But this fails as well, with a MockException saying:

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

However, if I step through the program, I can see that this method is called with a MyObject that has Contacts = 1.

Upvotes: 2

Views: 86

Answers (1)

Matt Cole
Matt Cole

Reputation: 2601

It's hard to say what might be causing your problem without seeing your [SetUp] code. I notice that your mocks and unit under test are member variables - maybe there is a problem with shared state with another test. I was able to write the same test, and have it pass consistently

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

Upvotes: 2

Related Questions