tags:

views:

50

answers:

3

Most examples I see of Unit tests are simple tests like Assert.That(5, 2 + 3), but how would I incorporate a unit test a method that gets a users information and saves them to a database. For example, I have a Register method that takes a User object. The User object properties are populated from a web form and then it is saved to the database. What are some viable unit tests that I could do with this?

Here is an example. Assume that the User object has some required fields such as Email, FirstName, LastName. Would a valid unit test assert that Email is not null or empty. The same applies to other required fields. So in my scenario above, would this be a unit test.

[Test]
public void EmptyEmailShouldReturnError()
{
   User user = new User();
   user.Email = "";
   //Set other properties

   //Not sure of nunit syntax here, so I will make something up.
   Assert.IsNotEmpty(user.Email);

}
+3  A: 

Those are not unit tests. Unit test are for testing things in isolation. Things that interact directly with a database cannot be tested in isolation as they depend on this database. If you want to test things in isolation you need to introduce levels of abstractions to avoid the strong coupling between your components. In a unit-test a common technique is to replace some component with a mocked object. This is possible only if you have abstracted your database access layer for example.

Now back to the question. How do you test your database access layer? Those are called integration tests. There are many techniques for performing integration tests with a database. Some of them consist of having a test database which is recreated in the Setup method and dropped in the TearDown method, so that all the tests assume some valid state to work with. So you might have some scripts that create and fill the database with test data and those scripts are called before running each test. You could even wrap everything inside a database transaction which will be rolled back at the end.

Darin Dimitrov
+2  A: 

Well, it depends on what you are trying to "unit" test.

  • Are you testing business logic which verifies that the user being created is valid?
  • Are you testing the database access layer (DB access code and/or stored procs)?
  • Do you want to test both at the same time?

If you want to test the business logic, then you can mock up your database access layer and then verify that the correct things were being passed to the database layer.

If you want to test the database layer, then create a test database which unit tests can write and read to.

If you want to test both then create a test database, run the business logic to create a user. Then query for that user, and validate all the data on it. This is more than just a "unit" test, but it is a valid test which can be done within the unit testing framework.

tster
+1  A: 

I don't think you really mean "unit test" in the strict sense of the word (involving a database or anything else beyond the method itself makes it an "integration" test), but if I were creating an automated test for the method you mention, I would make a test that creates the User object, passes it into the Register method, and then retrieves the User from the database and checks it against the original object to ensure that they are exactly the same. The last step would likely involve some Assert calls.

You also want other tests--a null parameter test to see what happens when a null object is passed in, and perhaps some tests that use various kinds of "weird" data to see how the method handles all your use cases.

SuperNES
Well, I know that if I talk to a database or use some external resource, it is more of an integration test, so in the case of my example, I can't do a unit test on it or would passing a null object to register be a unit test? For example, Register's signature is Register(User user). Would a unit test be something like. NullUserPassedtoRegisterShouldReturnError where I would Assert on the value of null and the User object passed in.
Xaisoft
The test I described in my first paragraph would be a valid unit test (since it only tests one method and nothing else) if it weren't for that pesky database. If you want to unit test the intended functionality of the method and not just how it reacts to weird parameters (all of which are valid unit tests--the main criteria for a unit test is that it only tests one thing), you need to take the database out of the equation. You'll really only be able to do this if you've abstracted the data layer out of the class you're testing.
SuperNES
Look at my updated post and see if that makes sense.
Xaisoft
Yes! That is a valid unit test, but it's only one of many similar unit tests you'd want for this method.
SuperNES