Tobias Kullblikk
Tobias Kullblikk

Reputation: 226

How can I avoid persisting unit test data?

I have a ASP.NET core (.NET Framework) project set up with Entity Framework for working with my database. I have created a seperate project for tests in my solution.

How will I go about writing unit tests for endpoints like 'register', 'signin', etc. ?

Here is a snippet of my RegisterUser endpoint.

public async Task<IActionResult> RegisterUser(string email, string name, string password)
    {
        var user = new User { UserName = email, Email = email, Name = name };

        IdentityResult resultCreate = null;

        if (email.EndsWith("@stud.ntnu.no") || email.EndsWith("@ntnu.no"))
        {
            // Student or teacher?
            var role = (email.EndsWith("@stud.ntnu.no") ? "Student" : "Teacher");

            resultCreate = await _userManager.CreateAsync(user, password);
            if (resultCreate.Succeeded)
            {
                // Add role
                var resultRole = await _userManager.AddToRoleAsync(user, role);

                if (resultRole.Succeeded)
                {
                    // Sign in
                    await _signInManager.SignInAsync(user, true);

                    return Ok();
                }

            }
        }

        // Error
        return StatusCode(400, resultCreate?.Errors);
    }

Upvotes: 0

Views: 312

Answers (1)

Mike Nakis
Mike Nakis

Reputation: 61993

Judging by the comments below the original post, the actual question appears to be "How can I avoid persisting unit test data?"

There is a number of ways you can go about it:

The hard-core, true-to-the-books, dogmatic unit-test way:

Unit tests should test only one thing, and everything else should be mocked. So, mock your _userManager and your _signInManager. Since they are mocked, they don't persist anything, so the avoidance of test data persistence comes for free. In my experience this is a rather retarded way for testing almost anything, and I strongly advise against it.

The rest of the approaches begin with the realization that you are not actually writing unit tests, you are writing integration tests, because you are testing your application logic in integration with your database layer.

The in-memory-database way:

Use an in-memory-database, and have each test create a new database which is thrown away at the end of the test. Unfortunately, this means restarting your entire database layer, and if you are using something heavyweight like an ORM, it means that a huge performance overhead will be added to each test.

The transactional way:

Have each test method start a transaction, and once it is done, roll it back. This is the preferred way of doing things. Under certain conditions you might even be able to annotate your test methods with @Transactional, and if all the rest of the required magic is right, then transactions might be taken care of for you. Then again, with annotations you never know whether something will really happen, and in this case if the transactionality does not happen then you are ruining your database, so my preference is to stay clear from @Transactional and code my transaction-begins and transaction-rollbacks myself.

Upvotes: 2

Related Questions