Part 2 Follow Up: But those tests suck!?!

In Part 2 of Automating Unit Tests with a Base Class I provided a set of example tests for CRUD operations.  Although the logic is correct the implementation...kinda....well....sucks!  The main problem is that many of the tests are dependent on functionality that is not directly being tested within the test method.  As an example let's look at the CanBeRead() test...

1 public void CanBeRead() {
2
3   Customer savedCustomer = new Customer();
4   // ...set properties
5
6   Assert.IsTrue(savedCustomer.Save());
7
8   // read the customer
9   Customer readCustomer = new Customer();
10   readCustomer.Load(savedCustomer.CustomerID);
11
12   // check properties of the loaded object against the saved object
13   Assert.AreEqual(savedCustomer.ContactName, readCustomer.ContactName, "ContactName properties are not equal.");
14   Assert.AreEqual(savedCustomer.ContactTitle, readCustomer.ContactTitle, "ContactTitle properties are not equal.");
15   Assert.AreEqual(savedCustomer.Address, readCustomer.Address, "Address properties are not equal.");
16
17   // check remaining properties as necessary...
18 }

In order to test the “read“ of the object the test first calls the .Save() method on the customer object.  If the .Save() method fails we get a failure for that test and will quickly assume our read logic is incorrect.  Unfortunately by including the .Save() within the read test we get an inaccurate view into what is causing problems within our application.  A better approach is to manually insert the records  using a SQL statement.  This prevents a failure in the .Save() from crashing our read test and ensures our tests only fail for a single reason.

So why did I present the test this way?  Believe it or not I'm actually using code very similar to this in my test projects.  Rather then calling INSERT's to place my test data in my database I'm using the .Save() method on my objects.  This allows me to quickly test my objects and also makes the base unit test which I'm sure you are all anxiously awaiting easier to implement.  Perhaps after I present my solution to automating the unit tests for CRUD operations I can clean the code up and implement a base test class that uses SQL statement to perform the necessary population and removal of test data. 

Have I lost all my TDD/Unit Testing “street cred” by coming out of the closet and admitting to this heinous crime? :-(

# re: Part 2 Follow Up: But those tests suck!?!

Sunday, June 06, 2004 4:25 AM by Frans Bouma    
As I dealt with this prob today as well (being in the middle of porting my massive testapp to NUnit tests) I can say that I don't see the need for manual SQL.

I use a special crafted testdatabase with all the db constructs I could think of, and each table has an extra ID, GUID, for the testrun ID. After each complete testrun I call a stored proc (hehe) and pass the GUID of that testrun to clean up the mess.

However each test first places testdata into the db and then tests logic to get the stuff out. I have also tiny tests for the insertion alone, which should succeed of course, as well. Now, because these inserts have to succeed as well, I don't see why they can't be a part of a fetch test: the save test will fail later one anyway, so you will see what's going on, plus you'll get an error that the save failed in the fetch test. I think that by including Saves using framework logic into fetch tests, you test the saves again, nothing wrong with that I think :)

# re: Part 2 Follow Up: But those tests suck!?!

Sunday, June 06, 2004 4:32 AM by Steve Maine    
Some people might beat you with the TDD stick, but I won't :)

As you pointed out, having interdependancies between tests means your tests have multiple points of failure. It's not the purest solution, but it can be worth the tradeoff -- keeping all those INSERT statements maintained just so you can avoid a call to Save() can lead to a lot of redundant work.

I would suggest putting your precondition code inside of a [SetUp] method. You can assert the call to Save() there, just like your doing in your test code. However, if that assert fails, you'll get a different error message than if an assertion fails within the test itself. It's effectively a single point of a failure -- sort of the best of both worlds.

# re: Part 2 Follow Up: But those tests suck!?!

Sunday, June 06, 2004 4:37 AM by Steve    
I guess I better watch my back! ;)

I used to attempt the INSERT statement route but it gets old fast. My objects do need to be able to save so it doesn't seem all that bad to have that tested (again) during "read" tests. I definitely agree that I should move it into the [SetUp] to create a single point of failure.

# Automating Unit Testing With a Base Class Posts

Saturday, June 19, 2004 1:38 PM by Steve Eichert    
Automating Unit Testing With a Base Class Posts

Post a Comment

 
 
Prove you're not a spammer: 
9 + 8 =