Testing the NuSoft Framework

posted on 07/09/08 at 12:45:25 am by Joel Ross

NuSoftFrameworkI've started up a new project that is using the NuSoft Framework, and because of some of the interactions, I realized it would be much, much easier if I had a set of automated tests, rather than going through the process of firing up an application, going through a WCF service, and then eventually hitting the code I needed to test.

I realize this isn't earth shattering for those used to doing TDD or unit testing, but it's not something that I've done a lot of in the past. On one project, we had well north of 100 tests, but they were all isolated to a particular hairy part of the code and it was rather self-contained.

To be honest, the NuSoft Framework is not ideal for unit testing, since the data persistence is pretty well embedded into the entities. That's OK in my mind, since I've rarely seen a case where my persistence layer has changed. Once, I knew I had to build for different databases, but that was known up front, and not added after the fact. That may be viewed as a naive attitude, but it's worked for me so far.

Anyway, there's a reason I didn't call this "unit testing" but rather referred to it as just testing. It's not unit testing, since it's not testing just one thing. It's more like an integration test, since it's also going to rely on a known state of the database.

Essentially, what you have to do is manage your own transaction, and then at the end, after you assert that your desired action worked, you roll it back, leaving the database untouched. If you want to isolate your tests in their own assembly, you're going to need to add an attribute to your business layer so you can gain access to some of the internals of the business layer:

   1:  [assembly: InternalsVisibleTo("Northwind.Tests")]

This gives us the ability to call one of the internal overloads on Save() where you can pass in a helper. This ensures the Save will participate in the existing transaction, and not create its own (which it does when you call Save() with no parameters). Here's an example that would test being able to insert a customer:

   1:  [Test]
   2:  public void CanInsertCustomer()
   3:  {
   4:    Customer customer = Customer.CreateCustomer();
   5:    customer.CustomerId = "jross";
   6:    customer.FirstName = "Joel";
   7:    customer.LastName = "Ross";
   8:   
   9:    using (SqlHelper helper = new SqlHelper())
  10:    {
  11:      try
  12:      {
  13:        helper.BeginTransaction();
  14:        customer.Save(helper);
  15:        Assert.That(customer.IsNew == false, "customer.IsNew was true but should have been false.");
  16:      }
  17:      finally
  18:      {
  19:        helper.Rollback();
  20:      }
  21:    }
  22:  }

The difference between this code and the code you would normally use is that you wouldn't manage your own helper and you'd call customer.Save(), not customer.Save(helper). If you dig into the guts of Save() with no parameter, you'll see it does essentially what I'm doing here. It creates a SqlHelper and opens the transaction. The difference is that if the insert works, the transaction is committed, and here the transaction is always rolled back, ensuring that the database isn't affected and leaving it in a known state for other tests.

I'm still new to automated testing, but it definitely does make being able to change existing code much easier and give me more confidence when I am doing that. And seeing all of the green lights in NUnit feels pretty good too.

Oh - the NuSoft Framework has a logo now (the one at the top of this post). What do you think of it?

Categories: Development, C#, RCM Technologies

5 comments »


 

5 comments

Comment from: Mark Jordan [Visitor] Email · http://www.markjordan.org
I'm not sure that I would extend the effort to test the persistance of the framework, unless we were testing an adaption/provider pattern to accomodate for different DB servers, or testing DB server-side features such as triggers. Testing the persistance of a DB seems superfluous to me since my continual testing during development will determine that validity.

I would certainly recommend a host of unit tests for the validation of the entities' business logic. For instance, testing if an Order has to have at least one order line in order to be saved. This can be accomplished without attempting to do a .Save(), and instead concentrating on the new .GetValidationErrors() method.

Just my opinion... gon't hate me for it 8^).
07/10/08 @ 09:28
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
Mark,

The example was probably a bad one in it's simplicity. But, those are the types of tests that we could generate as part of the framework if we wanted to.

I do, however, disagree that we shouldn't be testing the actual persistence. On just about every project I've used the NuSoft Framework on, I've had a need to either override or handle one of the "On" events that fires as part of the Save() - since we don't have a way to test them independently, this is the best I can come up with - for now.

I actually did - within an hour - modify the code so that I could mock the data layer completely, meaning I could test just what I wanted to test and not worry about the database. More on that later.

Joel
07/10/08 @ 10:32
Comment from: Mark Jordan [Visitor] Email · http://www.markjordan.org
Good point regarding the testing of overrides on the persistance methods.
07/10/08 @ 10:43
Comment from: Kalle Hoppe [Visitor] Email · http://www.nansen.se
"I actually did - within an hour - modify the code so that I could mock the data layer completely, meaning I could test just what I wanted to test and not worry about the database. More on that later."

That seems like the answer I was waiting for (question from Codeplex http://www.codeplex.com/Thread/View.aspx?ProjectName=kineticframework&ThreadId=45360). Can you use a mocking framework like RhinoMocks now?
It would be great if you could release the new version for testing.

Cheers!
/Kalle
01/28/09 @ 08:53
Comment from: Joel Ross [Member] Email · http://www.rosscode.com
Kalle,

The changes I made to allow you to mock out the IDataReader are in the trunk. There's a seam there to have the framework get an instance of IDataReader from your own factory, and you can just mock that out with RhinoMocks.

Mocking IDataReader is not fun, and takes a while to get the interactions correct, but it can be done.
01/28/09 @ 09:04

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)