Savail
Savail

Reputation: 867

C# integration tests with Entity Framework and async methods

I'm using separate test database for testing buisness logic purposes. My business logic however consists of mainly asynchronous methods which await on other methods multiple times. I'm having problems with testing such methods and I'm running out of ideas what's the cause and how to fix it...

Here's an example of a buisness logic method that I want to test:

public async Task<string> RegisterNewUser(string name, string surname, string address, string city, string phone, string email, string password, string repeatedPassword)
{
    string errorMessage = null;

    Person newUser = new Person();

    // _context is my instance of my class inherited from DBContext
    //Getting the next ID for new user
    if (_context.People.Any())
        newUser.Id = await _context.People.MaxAsync(record => record.Id) + 1;
    else
        newUser.Id = 0;

    newUser.Name = name;
    newUser.Surname = surname;
    newUser.Address = address;
    newUser.City = city;
    newUser.Phone = phone;
    newUser.Email = email;
    newUser.Password = password;

    bool validationSuccessful = true;

    if (await _context.People.CountAsync(p => p.Email == newUser.Email) > 0)
    {
        errorMessage = "Given email address is already taken";
        validationSuccessful = false;
    }

    if (validationSuccessful)
    {
        try
        {
            // Adding user to database
            newUser.Password = GetHashedPassword(newUser.Password);
            _context.People.Add(newUser);

            // Adding activation info to database
            RegistrationActivation act = new RegistrationActivation() { PersonId = newUser.Id, ActivationKey = "blabla"};
            _context.RegistrationActivations.Add(act);

            await _context.SaveChangesAsync();
        }
        catch (Exception e)
        {
             Exception exc = e;

             while (exc.InnerException != null)
             {
                 exc = exc.InnerException;
                 errorMessage = "Exception - " + exc.Message;
             }
        }

        return errorMessage;
    }
}

Here's my actual test method:

[TestMethod]
public void Login()
{
    Person registered = PersonTestData.CreateGoodTestUser();

    string error = UnitOfWork.CrudServices.MyPersonRepository.RegisterNewUser
                (registered.Name, registered.Surname, registered.Address, registered.City, registered.Phone, registered.Email, registered.Password, registered.Password).Result;

    Assert.IsTrue(error == null, error);
}

UnitOfWork in the code above is just an object instantiated for each test method at the begining and disposed after it completes. It connects with the test database and gives access to buisness logic methods in repositories.

In the current form the test is going to fail with exception in RegisterNewUser with message: Awaiting operation time limit exceeded or sth like this becouse it's translated into my native language...

Now if I comment out the code for adding a user and adding activation info (4 lines right before _context.SaveChangesAsync()) the test will be passed. Furthermore if I remove all async / await functionality from the RegisterNewUser method - that is not using await and using methods without Async suffix without deleting lines mentioned above - the test is going to be passed as well...

I would be really grateful if somebody could shed some light into this problem.

Upvotes: 0

Views: 1106

Answers (1)

Brad
Brad

Reputation: 4553

Stephen Cleary has all the answers you need when it comes to async anything - http://blog.stephencleary.com/2012/02/async-unit-tests-part-2-right-way.html.

Besides Stephen's excellent advice for async unit testing you could also try using XUnit which supports async unit testing methods out of the box e.g.

[Fact]
public async void MyTest() 
{
    var temp = await SomeAsyncMethod();
}

Upvotes: 1

Related Questions