How To Unit Test – Linq to SQL and Mocking

All problems in computer science can be solved by another level of indirection Butler Lampson (Or Abstraction as some people refer to it as)

Over the last few posts, I have been covering how to unit test various topics, in this post I will cover Linq to SQL. I’ve been thinking about this for a while, but never had chance to post about it. Various people have spoken about this before, but I thought I would give my view.  I’m going to discuss how to unit test systems involving Linq to SQL, how to mock Linq to SQL, how this will come into play with the new ASP.net MVC Framework and how TypeMock might have the answer.

Scenario

For this post, I decided to implement a small part of a shopping cart.  You can return a list of categories, a list of products for each category and the product itself.

Unit Testing Linq to SQL

In my previous post, I discussed how to unit test Linq to XML and mentioned how it really isn’t that different to any other system.  Linq to SQL is similar in the fact that you can easily ignore the underneath implementation (Linq) when unit testing, however I’m going to focus more on how to decide the system and how it all should hang together.

Like in any Linq to SQL implementation you will need a data context.  While you could unit test this implementation, I always prefer to test it as part of a higher layer as its generated code to give the tests more context and more meaningful for the system. The most important part of the system will be how we actually access the DataContext, retrieve the data and make sure that it can be effectively unit tested.

In my system I will have my HowToUnitTestDataContext generated by the Linq to SQL Designer.  I will then have a ProductController which will talk to my DataContext and return the generated object. Unlike with SubSonic, we can return the designer generated objects as they are just POCO (Plain Old C# Objects).  I will then have a set of unit tests targeting the ProductController.  We are not doing any mocking at this point and all of our unit tests will hit the database.

First test, create a data context and ensure it has a connection string.  This ensures everything is setup correctly.

[Test]
public void CreateDataContext_ConnectionString_ReturnsDataContextObject()
{
    HowToUnitTestDataContext db = ProductController.CreateDataContext();
    Assert.IsNotNull(db);
    Assert.IsNotNull(db.Connection);
}

All the method does is initialise a data context and return it to the caller. The next test requests a list of all the categories from the database.  However, because we haven’t populated anything yet it should just return an empty list.

[Test]
public void GetCategories_NoContent_ReturnEmptyList()
{
    List categories = ProductController.GetCategories();
    Assert.IsNotNull(categories);
    Assert.AreEqual(0, categories.Count);
}

We now have a base structure in place and can start filling in the details. The following test first inserts a category into the database (code is in the solution which you can download at the bottom of the post).  It then requests all the categories from the database and ensures that what we returned was correct. We then use the MbUnit RollBack feature to ensure the database is left in the same state as it was before the test. The rollback works perfectly with Linq to SQL!

[Test]
[RollBack]
public void GetCategories_SimpleContent_ReturnPopulatedList()
{
    InsertCategory();

    List categories = ProductController.GetCategories();
    Assert.IsNotNull(categories);
    Assert.AreEqual(1, categories.Count);
    Assert.AreEqual(“Microsoft Software”, categories[0].Title);
}

The code for GetCategories() is a simply Linq to SQL statement which returns a generic list.

public static List GetCategories()
{
    HowToUnitTestDataContext db = CreateDataContext();
    var query = from c in db.Categories
                       select c;
    return query.ToList();
}

The next important test is the one which returns product information.  Here, we use a tested GetCategory method to return a particular category. We then insert a temp product into the database for that category, meaning that we now have a known database state to work with. The test then simply verifies that when given a category we can return all the products in the database for it.

[Test]
[RollBack]
public void GetProductsForCateogry_ValidCategoryWithProduct_PopulatedList()
{
    InsertCategory();

    Category c = ProductController.GetCategory(“Microsoft Software”);
    InsertProduct(c);

    List products = ProductController.GetProductsForCategory(c);
    Assert.AreEqual(1, products.Count);
    Assert.AreEqual(“Visual Studio 2008”, products[0].Title);
}

The implementation of this method is a little bit more complex as it joins a ProductCategories table to return the products within the particular category.

public static List GetProductsForCategory(Category c)
{
    HowToUnitTestDataContext db = CreateDataContext();
    var query = from p in db.Products
                       join pc in db.ProductCategories on p.id equals pc.ProductID
                       where pc.CategoryID == c.id
                       select p;

    return query.ToList();
}

The final method is to return a particular product based on its ID.  It works in a similar fashion to the previous methods.

[Test]
[RollBack]
public void GetProductByID_ValidProductID_ReturnProductID()
{
    InsertCategory();

    Category c = ProductController.GetCategory(“Microsoft Software”);
    InsertProduct(c);

    List products = ProductController.GetProductsForCategory(c);
    Assert.AreEqual(1, products.Count);

    Product p = ProductController.GetProduct(products[0].id);
    Assert.AreEqual(p.Title, products[0].Title);
}

In the implementation we then just return a single product using a lambda expression.

public static Product GetProduct(int productID)
{
    HowToUnitTestDataContext db = CreateDataContext();

    Product product = db.Products.Single(p => p.id == productID);
    return product;
}

That pretty much covers unit testing basic Linq to SQL. Other parts of the system, such as the business layer or UI layer, can then talk directly to the ProductController to return all the information. However, this doesn’t offer anything if you want to mock out Linq to SQL.

Mocking Linq to SQL

Unit testing Linq to SQL isn’t very difficult, however mocking Linq to SQL is a different beast. As with SubSonic, the best approach to take is to abstract away from your database. In this case, I am going to add an additional layer in between my ProductController and my DataContext called LinqProductRepository which can then be mocked. 

My first set of tests are focused on testing the LinqProductRepository which talks to my DataContext and as such my database. The tests are very similar to the above tests for ProductController. I always test this against the database to ensure that it will work effectively when its in production/live, with mock objects you can never have the same level of confidence.

LinqProductRepository m_ProductRepository = new LinqProductRepository();
[Test]
[RollBack]
public void GetCategoryByName_NameOfValidCategory_ReturnCategoryObject()
{
    InsertCategory();

    Category c = m_ProductRepository.GetCategory(“Microsoft Software”);

    Assert.AreEqual(“Microsoft Software”, c.Title);
    Assert.AreEqual(“All the latest Microsoft releases.”, c.Description);
}

To give you an idea of the implementation, the GetCategory method looks like this:

public Category GetCategory(string categoryTitle)
{
    using (HowToUnitTestDataContext db = CreateDataContext())
    {
        Category category = db.Categories.Single(c => c.Title == categoryTitle);
        return category;
    }
}

In order to make the ProductRepository mockable it is required to implement an interface.  The interface is very simply, as shown:

public interface IProductRepository
{
    List GetCategories();
    Category GetCategory(string categoryTitle);
    List GetProductsForCategory(Category c);
    Product GetProduct(int productID);
}

We now have a fully implemented and tested ProductRepository so we can create the ProductController. To start with, in my ProductControllerTests I setup the variables and the [Setup] method for each test.  This ensures that we have our MockRepository (via RhinoMocks) to hand, a copy of our mocked IProductRepository together with our stub category and product.  These two objects are simple well known objects (for the system) which we will return from our mocked methods.  I’m using parameter injection to set the mocked repository on the ProductController which will be used during the tests. By using a parameter we can have a default implementation for our production code but a way for our test code to injection the mock object.

MockRepository m_Mocks;
IProductRepository m_ProductRepos;
Category m_MockedCategory;
Product m_MockedProduct;

[SetUp]
public void Setup()
{
    m_Mocks = new MockRepository();
    m_ProductRepos = m_Mocks.CreateMock();
    ProductController.ProductRepository = m_ProductRepos;

    m_MockedCategory = MockCategory();
    m_MockedProduct = MockProduct();
}

We can then write our unit tests based on this information which will be similar to our previous units tests as they are implementing the same requirements. Within this test, we setup our expected return for the method GetCategories on our ProductRepository, this simply uses C# 3.0 Collection Initialises to create a list with one item, the stub category. We can then execute our test/asserts against the ProductController to view it is all linked correctly and working as expected.

[Test]
public void GetCategories_SimpleContent_ReturnPopulatedList()
{
    using (m_Mocks.Record())
    {
        Expect.Call(m_ProductRepos.GetCategories()).Return(new List { m_MockedCategory });
    }

    using (m_Mocks.Playback())
    {
        List categories = ProductController.GetCategories();
        Assert.IsNotNull(categories);
        Assert.AreEqual(1, categories.Count);
        Assert.AreEqual(“Microsoft Software”, categories[0].Title);
    }
}

The ProductController simply passes the call onto our ProductRepository, which is set using a parameter in our test Setup.

private static IProductRepository m_ProductRep = new LinqProductRepository();

public static IProductRepository ProductRepository
{
    get { return m_ProductRep; }
    set { m_ProductRep = value; }
}

public static List GetCategories()
{
    return ProductRepository.GetCategories();
}

This allows us to use the ProductController with a mock object. ProductController could be/do anything and by going via the LinqProductRepository we can use mock objects to save us accessing the database.  In our real system, we would use the real tested LinqProductRepository object.

ASP.net MVC and Linq to SQL

Recently there has been a lot of buzz around the new ASP.net MVC framework the ASP.net team are releasing (CTP soon).  If you haven’t read about this, Scott Guthrie has done a great post on the subject.

However, Scott Hanselman did a demo of the MVC framework at DevConnections and has posted the source code online here – DevConnections And PNPSummit MVC Demos Source Code. Demo 3 and 4 is about TDD and uses mock objects and Linq to SQL.

The layout is as follows:

ASP.net MVC

The BlogController talks to a IPostRepository object which is either LinqPostRepository or TestPostRepository. They use a Stub object instead of a mock object, but the architecture is the same as my system. I would just like to say I didn’t just copy them 🙂

From this demo code, it looks like the way to mock your data access layer will be to use this approach.

Mocking the DataContext

The thing which first struck me about this was why couldn’t we just mock the DataContext itself instead of messing around with Repositories and Controllers. The first answer was that it didn’t implement an interface, but that’s a simple fix.  The second problem is that the data context returns everything as System.Data.Linq.Table<>, and this cannot be mocked. It does implement an ITable interface, however you cannot cast another object implementing ITable to Table.

Ayende, creator of Rhino Mocks, wrote a post called Awkward Testability for Linq for SQL which covers why it cannot be mocked.  Its a shame the Linq team didn’t think about TDD and Mocking the repository as it would have made a big difference to the system design. Maybe this is a lesson for anyone creating an API at the moment – think about testability! I think the ASP.net team have realised this.

Mocking with TypeMock

That all said, it looks like TypeMock might be able to provide an answer.  TypeMock is a mocking framework, however is extremely powerful as it can mock any object within your system, it doesn’t care about the implementation or if there is an interface available. It can simply mock anything.  I will be looking at TypeMock more over the next few weeks, but before then visit their site. It’s not free (30 day trail available), but if you need to do this type of mocking then it really is your only solution and it can greatly increase your test coverage and your test suite as a whole.

You can read the initial ideas over on their blog – Eli Lopian’s Blog (TypeMock) » Blog Archive » Mocking Linq – Preview.  Going in depth on TypeMock and Linq deserves its own post, however I couldn’t resist posting some code now.

Below, we have a test which mocks out querying a simple list.  Here, we have a list of customers and a dummydata collection. Our actual Linq query is against the m_CustomerList, however TypeMock does some ‘magic’ under the covers and tells the CLR that the query should just return the dummyData. As such, instead of just returning the one customer record, we are returning the two dummy data records. How cool!!!

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

[Test]
[VerifyMocks]
public void MockList()
{
    List m_CustomerList = new List {
        new Customer{ Id = 1, Name=”Dave”, City=”Sarasota” },
        new Customer{ Id = 2, Name=”John”, City=”Tampa” },
        new Customer{ Id = 3, Name=”Abe”, City=”Miami” }
    };

    var dummyData = new[] {new {Name=”fake”,City=”typemock”},
               new {Name=”another”,City=”typemock”}};
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
        // Mock Linq
        var queryResult = from c in m_CustomerList
                          where c.City == “Sarasota”
                          select new { c.Name, c.City };
        // return fake results
        recorder.Return(dummyData);
    }

    var actual =  from c in m_CustomerList
                  where c.City == “Sarasota”
                  select new { c.Name, c.City };
    Assert.AreEqual(2, actual.Count());
}

But it gets better!  Given our original ProductController (no repositories, mocks, fakes, stubs) we can tell TypeMock that for this statement, always return the dummyData. As such, the ProductController never hits the database.

[Test]
[VerifyMocks]
public void MockDataContext()
{
    Category category = new Category();
    category.id = 1;
    category.Title = “Test”;
    category.Description = “Testing”;

    List dummyData = new List { category };
    using (RecordExpectations r = RecorderManager.StartRecording())
    {
        // Mock Linq
        List mocked = ProductController.GetCategories();
        // return fake results
        r.Return(dummyData);
    }

    List categories = ProductController.GetCategories();
    Assert.AreEqual(1, categories.Count);
    Assert.AreEqual(“Test”, categories[0].Title);
    Assert.AreEqual(“Testing”, categories[0].Description);
}

Feel free to download the solution and debug the methods to see it for yourself, I think its cool.

Summary

In summary, I hope you have found this post useful and interesting. I’ve covered how to unit test your Linq to SQL code and how you go about mocking Linq to SQL. I then finished by giving you a quick look at what TypeMock can offer. It is possible to mock Linq to SQL, however it’s not as simple as it could be. If you have any questions, please feel free to contact me.

Download Solutions – TestingLinqToSQL.zip | TestingLinqToSQLMock.zip | TestingLinqToSQLTypeMock

How To Unit Test – Linq To XML

Now that I’m back from TechEd, it’s time to continue my series of “How To Unit Test” posts.  In this post, I’ve decided to have a quick look into Linq to XML and how that could be unit tested.  I’ve decided to pick the nice standard sample for Linq to XML – A Rss Reader :).  This also follows on nicely from my previous post on How To Unit Test Using SubSonic and Rhino Mocks

Unit testing Linq to Xml is no great big secret. The fact that you are performing Linq queries under the covers doesn’t really affect your unit tests, but it’s still quite interesting.

To start with, I’m going to be using the BBC News feed as my sample xml feed to query. My first test is to return an RssChannel object which had a url and title.  Note, I’m not implementing all the properties as that would get very boring very quickly.

[Test]
public void GetRssChannel_StandardRss_ReturnDataRssChannel()
{
    RssProcessor rss = new RssProcessor();
    RssChannel chan = rss.GetRssChannel(TestHelper.url);
    Assert.AreEqual(TestHelper.url, chan.Url);
    Assert.Contains(chan.Title, “BBC”);
}

The implement on the method then simple queries a XDocument, creates my RssChannel object and returns it to the caller.

public RssChannel GetRssChannel(string url)
{
    XDocument x_Feed = XDocument.Load(url);
    var feeds = from f in m_Feed.Elements(“rss”).Elements(“channel”).Take(1)
                       select new RssChannel
                       {
                           Title = f.Element(“title”).Value,
                           Url = m_Url
                       };

    return feeds.First();
}

The next method does a similar function but returns a RSSItem for the position in the document (Linq to XML is great for doing queries like this).

[Test]
public void GetRssItem_RssFeed_ReturnsASingleRSSItem()
{
    RssProcessor rss = new RssProcessor();
    RssItem item = rss.GetRssItem(TestHelper.url, 1);
    Assert.IsNotNull(item);
    Assert.IsNotNull(item.Title);
}

The query would be:

var feeds = from f in m_Feed.Elements(“rss”).Elements(“channel”).Elements(“item”).Skip(itemPosition – 1).Take(1)
            select new RssItem
            {
                Title = f.Element(“title”).Value
            };

Instantly we can see from the tests that we can do a bit of refactoring.  Firstly, we can move the creation of the RssProcessor into a [Setup] method.  We can also give the Url for the feed as a parameter in the constructor.  This makes our test code cleaner as there is less duplication, but also more readable as we are focusing more on the intent of the tests.

The complete solution can be downloaded at the end of the post, however there is one more test which I want to refer to.

The following returns an RssFeed object which has a reference to the RssChannel and a List.

[Test]
public void GetRssFeed_EntireFeed_ReturnsChannelAndItems()
{
    RssFeed feed = m_Rss.GetFeed();
    Assert.IsNotNull(feed.Channel);
    Assert.Contains(feed.Channel.Title, “BBC”);
    Assert.GreaterThan(feed.Items.Count,0);
}

The test works fine, however based on the implementation on the existing tests, each method loads their own Rss feed/XDocument. This is great for isolation, but doesn’t work well when you put it all together as loading a single feed will cause it to actually be loaded three times – that simply doesn’t scale.

The solution was to have a LoadFeed method on the RssProcessor which would be called before GetFeed().  This could also allow for a single object to be used for returning multiple feeds.  Note for future: My first test should really have been for this method to make sure I can actually receive an object to work with before querying it.

m_Rss.LoadFeed(TestHelper.url);

Having this single method as the way to load and return the Xml makes mocking very easy. Following the approaches in previous posts, I created myself an IFeedGetter object, with a property to injection a mock if required on my RssProcessor.  The load method then simply passes it’s call onto the IFeedGetter object.

public XDocument LoadFeed(string url)
{
    m_Url = url;
    m_Feed = m_FeedGetter.GetXDocument(url);
    return m_Feed;
}

I can then create a stub feed getter to be used during unit testing.

public class StubFeedGetter : IFeedGetter
{
    public System.Xml.Linq.XDocument GetXDocument(string url)
    {
        return XDocument.Load(System.Xml.XmlReader.Create(new System.IO.StringReader(GetFakeXml())));
    }
}

So that’s it,  we have now unit tested our complete Rss implementation using mocks and Linq to XML!  If you need support in getting this to work, please give me a shout.

Download Solution: HowToUnitTest_MockLinq-ToXml.zip

Technorati Tags: , , ,

How To Unit Test – RegEx and Technorati

Following on from my previous post, I wanted to implement another feature in the blog application. The feature is to pick out the Technorati tags from a post and pull relates posts from the Technorati API.  I’ve already blogged about how to process the Technorati API.

To implement this feature, the first thing i’m going to have implement is being able to return a list of all the tags for a post.

I found unit testing RegEx really difficult.  I’m not great at RegEx as I only rarely have a requirement to do it and this is where unit testing becomes difficult.  Its easy to unit test code you have wrote before but unit testing code you haven’t done in a while takes a little more effort.  I feel the reason is because you are thinking about the design in your head to try and figure out how it all fits together.  During this implementation, I found the best thing to do was simply just start writing simple code and spike RegEx.  To spike RegEx I wrote a simple test which I thought should pass successfully based on my previous.

[Test]
public void RegExMatchesString()
{
    Regex r = new Regex(“http://technorati.com/tags/(.+?) rel=”tag”>(.+?)“);
    MatchCollection collection =
        r.Matches(“http://technorati.com/tags/TestCode” rel=”tag”>Test Code“);

    Assert.AreEqual(1, collection.Count, “Collection”);

    foreach (Match match in collection)
    {
        Assert.IsTrue(match.Success);
        Assert.AreEqual(2, match.Captures.Count, “Captures”);
        Assert.AreEqual(“TestCode”, match.Captures[0].Value, “One”);
        Assert.AreEqual(“Test Code”, match.Captures[1].Value, “Two”);
    }
}

This fails, so I knew I must have done something wrong. I then jumped quickly into the debugger, and found instead of using the Captures collection, I wanted the Groups collection. I retested it and found Groups actually includes both the two matches plus the whole thing. The whole thing is at 0 index in the collection so I had to move everything alone one.  A couple of minutes later I had my regex code working.  There’s nothing like seeing a test go green!  The actual implementation is below.

[Test]
public void Spike_RegExMatchesString()
{
    Regex r = new Regex(“http://technorati.com/tags/(.+?) rel=”tag”>(.+?)“);
    MatchCollection collection =
        r.Matches(“http://technorati.com/tags/TestCode” rel=”tag”>Test Code“);

    Assert.AreEqual(1, collection.Count, “Collection”);

    foreach (Match match in collection)
    {
        Assert.IsTrue(match.Success);
        Assert.AreEqual(3, match.Groups.Count, “Captures”);
        Assert.AreEqual(“TestCode”, match.Groups[1].Value, “One”);
        Assert.AreEqual(“Test Code”, match.Groups[2].Value, “Two”);
    }
}

Based on the code completed during the spike, I can quickly test and implement the code by refactoring out the important parts into actual unit tested methods.  Spending that bit extra time to look into the spike made the actual implementation a lot quicker and easier.

[Test]
public void GetMatchCollectionForHtml()
{
    string post = “http://technorati.com/tags/TestCode” rel=”tag”>Test Code“;
    MatchCollection collection = Technorati.GetMatches(post);
    Assert.AreEqual(1, collection.Count, “Collection”);
}

[Test]
public void GetListFromMatches()
{
    string post = “http://technorati.com/tags/TestCode” rel=”tag”>Test Code“;
    MatchCollection collection = Technorati.GetMatches(post);

    List tags = Technorati.GetTagList(collection);
    Assert.AreEqual(1, tags.Count);
    Assert.AreEqual(“TestCode”, tags[0]);
}

Once they work, I write a test to ensure it works together with ‘real’ data.

[Test]
public void GetTagListFromPostText()
{
    RssFeed rss = TestHelper.CreateMockRSS(TestHelper.url);
    RssItemCollection items = rss.Channels[0].Items;

    string post = items[0].Description;
    List tags = Technorati.GetTagListFromPost(post);
    Assert.AreEqual(3, tags.Count);
    Assert.AreEqual(“MbUnit”, tags[0]);
    Assert.AreEqual(“TDD”, tags[1]);
    Assert.AreEqual(“Testing”, tags[2]);
}

Great, that’s our tag list completed.  We now just need to pull the posts from Technorati.

My previous post wasn’t very testable, the method was doing a lot.  It was pulling data, processing the feeds and returning a list. This version has been separated into a lot smaller methods to make unit testing easier and more effective.  The first test is to make sure we can return a list of XmlNodes from the API.

[Test]
public void GetXmlFromRss()
{
    int limit = 10;
    string technoratiTerm = “MbUnit”;

    XmlNodeList xmlNodes = Technorati.GetXmlNodeList(Technorati.GetUrl(technoratiTerm));
    Assert.AreEqual(limit, xmlNodes.Count);
}

We then want to make a Blog object from one of the XmlNodes in the list.

[Test]
public void GivenXmlNodeCreateBlog()
{
    string technoratiTerm = “MbUnit”;

    XmlNodeList xmlNodes = Technorati.GetXmlNodeList(Technorati.GetUrl(technoratiTerm));
    Blog blog = Technorati.CreateBlogPost(xmlNodes[0]);
    Assert.AreEqual(blog.Title, xmlNodes[0][“title”].InnerText);
}

After that has been implemented, we can can a list of Blog objects from a list of nodes (it simply calls the above method multiple times).

[Test]
public void GetBlogPostListTerm()
{
    string technoratiTerm = “MbUnit”;

    XmlNodeList xmlNodes = Technorati.GetXmlNodeList(Technorati.GetUrl(technoratiTerm));
    List blogs = Technorati.CreateBlogPostList(xmlNodes);
    Assert.AreEqual(10, blogs.Count);
}

Finally, we can get a list of blog posts for a list of strings (again, calling the above method multiple times).

[Test]
public void GetBlogPostListForListOfTerms()
{
    List terms = new List(3);
    terms.Add(“MbUnit”);
    terms.Add(“TDD”);
    terms.Add(“Testing”);

    List blogs = Technorati.CreateBlogPostList(terms);
    Assert.AreEqual(30, blogs.Count);
}

The only problem with these tests is that they are hitting the Technorati API for each test.  It would be much better if we could abstract away from the API and use a stub object instead. A stub object allows us to replace the implementation however are they not as cleaver as a mock object and more limited, but for this simple task it will fit the purpose as using a full mock framework isn’t really required and similar the better really.

To do this, I’m going to inject the stub object the same way I would a mock object by using a static method on the Technorati object.  Within my test code, I use TechnoratiStub (Implemented within my test assembly, no test code inside the actual assembly under test).  In the real system I use TechnoratiAccessor.

Technorati.TechnoratiAPI = new TechnoratiStub();

private static ITechnoratiAccessor dataStore = new TechnoratiAccessor();
public static ITechnoratiAccessor TechnoratiAPI
{
    get { return dataStore; }
    set { dataStore = value; }
}

I then move the implementation of hitting the API and returning the XmlNodeList to the TechnoratiAccessor.

public interface ITechnoratiAccessor
{
    XmlNodeList GetXmlNodeList(string technoratiUrl);
}

public class TechnoratiAccessor : ITechnoratiAccessor
{
    public XmlNodeList GetXmlNodeList(string technoratiUrl)
    {
        XmlDocument xmlResultsSet = new XmlDocument();
        xmlResultsSet.Load(new XmlTextReader(technoratiUrl));
        XmlNodeList xmlResponse = xmlResultsSet.SelectNodes(“/tapi/document/item”);
        return xmlResponse;
    }
}

Then, in my Technorati object, I just return whatever the TechnoratiAPI gives me (be it the real implementation or the stub).

public static XmlNodeList GetXmlNodeList(string technoratiUrl)
{
    return TechnoratiAPI.GetXmlNodeList(technoratiUrl);
}

All of our tests still pass, so we can now implement the stub.  In all the tests I setup the property to point to the Stub and then the stub just loads a valid XML response I have cached in a string to a XmlDocument and return the XmlNodeList. Very quick and easy.

public class TechnoratiStub : ITechnoratiAccessor
{
    public XmlNodeList GetXmlNodeList(string technoratiUrl)
    {
        #region Xml
        string cachedXmlResponse = @”Too long to insert here”;
        #endregion

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(cachedXmlResponse);
        return xmlDoc.SelectNodes(“/tapi/document/item”);
    }
}

Now when all of our tests execute, they use this Stub object instead of the real API.  Hope you find this useful.

Downloads: TechnoratiTests.cs  ||  Technorati.cs  (These include all of the discussed in this post).

Technorati Tags: , , , ,

How To Unit Test – Using SubSonic and Rhino Mocks

“All problems in computer science can be solved by another level of indirection” Butler Lampson (Or Abstraction as some people refer to it as). 

This is one of the most used quotes within computer science and when it comes to talking about mock objects I think it is particularly true. 

As discussed in Part 1 and Part 2 of my articles on Rhino Mocks, attempting to mock part of the .Net framework is not worth the effort and it is better if you create a wrapper around the framework implementation and then mock the wrapper (adding another layer of abstraction).

In this post, I will outline one possible approach to using mock objects and Rhino Mocks with SubSonic.  There are other approaches, mainly focusing around MVC, however for this approach I want to keep it focusing on using SubSonic as a DAL without discussing MVC.

Scenario

In this post, I’m going to implement a rss aggregator/roller.  It will check blog posts, save any new posts into a database and then the application will pull the blog posts out of the database. 

The flow of data will be this:

RSS > Post Manager > Database > Post Manager ||  Application.

For the moment, I’m not interested in the UI, I will be building the API which could easily be used by an application.  The reason why I picked a blog aggregator is because it provides a interesting TDD/Unit Testing challenge.  Not only are we dealing with databases, which as we found out is difficult, but we are also pulling data from a 3rd party source via the internet.

Implementation

Let’s start implementing the solution.  For a RSS Aggregator, the most important thing really is to take a RSS Feed and process the contents.  Because we are using mocks, we can mock out the external RSS feed and just use a known valid response, at runtime this will be replaced with code which makes a call to the web server.  The most important thing to remember is to mock at the external boundary as its at this point we lose control over the execution.

Important considerations for the implementation

Before we start, there are some important considerations about the implementation which we should think about before writing tests/code.  One of the main things to remember is to keep everything isolated and focus on the task in hand, we need to make sure our methods and tests aren’t going off and breaking their boundaries.  When we are testing the Post Manager for obtaining the RSS Feeds, we don’t want to be hitting the database to see if it saves correctly as well. Next, we want to be sure we are mocking the correct object in the system.  There is no point mocking the Rss object if all it does is hold data, we want to be mocking the object directly related to the OUT (Object Under Test) which has it’s own set of related tests to ensure it works correctly.  The objects we generally want to mock out are objects which interact with external dependences, in this case the RssFeed on the web and the database.

Finally, we want to make sure that our tests are running independently of each other and cleaning up after themselves if they make any permanent charges.

With that said, The first requirement for the system is be able to get the xml for a url.

[Test]
public void GetXmlFromURL()
{
    RssFeed rss = PostManager.GetRssFeed(http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml);
    Assert.AreEqual(TestHelper.url, rss.Url);
}

The test simply says we want to access a static method on the PostManager called GetRssFeed and by giving it a url, we can return an RssFeed object. For my RSS objects, I will be using RSS.Net to save me implementing and testing the feed parsing (why build it when its already done).  I actually found this framework very easy to use and completely open source so you can modify it as you see fit (I did to make RssFeed.Url not read-only).  To implement the method on the PostManager, we call a method on the Rss.Net object.

public Rss.RssFeed GetRssFeed(string url)
{
    return RssFeed.Read(url);
}

Now we have a working implementation, it would be nice if we could mock obtaing the RSS instead of having to hit the rss feed every time we wanted to test the method.

[Test]
public void MockGettingRssFeed()
{
    //This is what we want our mock object to return to the calling code.
    RssFeed rss = TestHelper.CreateMockRSS(TestHelper.url);
    MockRepository mocks = new MockRepository();
    IFeedGetter feedGetter = mocks.CreateMock();

    using (mocks.Record()) //Setting up what we expect the mock object to do.
    {
        Expect.Call(feedGetter.GetFeed(TestHelper.url)).Return(rss);
    }

    using (mocks.Playback()) //Performing the test
    {
        PostManager.FeedGetter = feedGetter;
        RssFeed actualRss = PostManager.GetRssFeed(TestHelper.url);

        Assert.GreaterThan(rss.Channels.Count, 0);
        Assert.AreEqual(TestHelper.url, rss.Channels[0].Link.AbsoluteUri);
    }
}

In order for obtaining the RSS feed to be mocked out, I moved the GetFeed method into a IFeedGetter interface (implemented as FeedManager) and added a FeedGetter property to the PostManager object.  This allows me to use the default object (FeedManager) in the real system without changing the code, however during unit testing (or in the future) I can replace the default implementation with my own – in this case a mock IFeedGetter.

private static IFeedGetter feedGetter = new FeedManager();
public static IFeedGetter FeedGetter
{
    get { return feedGetter; }
    set { feedGetter = value; }
}

In order to keep the test code cleaner, I extracted the creation of the mock RssFeed object into a TestHelper method, this can then be called from multiple locations within my test code without having to manually create an object each time.  There is also a unit test associated with this method to make sure it works correctly.

Our implementation of FeedGetter and PostManager is complete.  Using Rss.Net allowed us to cut the implementation time.  Moving on, we need to be able to save this RssFeed object into the database. 

If you are not aware, an RSS is made up of general information about the feed (RssChannel) and then a number of items (RssItem).  To save the feed, the first thing we need to do is save the RssChannel object.

[Test]
public void InsertFeedDetailsIntoDatabase()
{
    using (mocks.Record())
    {
        Expect.Call(database.InsertFeedDetails(rssFeed.Channels[0])).Return(1);
    }

    using (mocks.Playback())
    {
        int recordID = DatabaseManager.InsertFeedDetails(rssFeed.Channels[0]);

        Assert.GreaterThan(recordID, 0);
    }
}

This method simple says that a method on the database object should accept an RssChannel object and return a 1 if its inserted correctly.  We them access this method via a DatabaseManager object.  For the test to be shorter, I moved a lot of the code into the [Setup] for the test fixture.

RssFeed rssFeed;
MockRepository mocks;
IDataStore database;

[SetUp]
public void TestSetup()
{
    rssFeed = TestHelper.CreateMockRSS(TestHelper.url);
    mocks = new MockRepository();
    database = mocks.CreateMock();
    DatabaseManager.DataStore = database;
}

Notice I’m setting the DataStore of the DatabaseManager to the IDataStore mock object via a property. One thing which I want to test for is to make sure that if the property hasn’t been setup correctly, then the correct exception is thrown.  This just saves any nasty surprises later.

[Test]
[ExpectedArgumentNullException]
public void ThrowExceptionOnSaveFeedIfNoDataSource()
{
    DatabaseManager.DataStore = null;
    DatabaseManager.SaveFeed(rssFeed);
}

Moving on, the next item to implement is saving an actual RssItem.   The test just makes sure that the InsertFeedItem is called twice, once for each RssItem in the collection.

[Test]
public void InsertFeedItemsIntoDatabase()
{
    int channelId = 1;
    using (mocks.Record())
    {
        Expect.Call(database.InsertFeedItem(channelId, rssFeed.Channels[0].Items[0])).Return(1);
        Expect.Call(database.InsertFeedItem(channelId, rssFeed.Channels[0].Items[1])).Return(2);
    }

    using (mocks.Playback())
    {
        bool result = DatabaseManager.InsertFeedItems(channelId, rssFeed.Channels[0].Items);
        Assert.IsTrue(result);
    }
}

Now we have both parts to save the feed in place, we can write another method which tests we can do both.

[Test]
public void InsertFeedIntoDatabase()
{
    int channelID = 1;

    using (mocks.Record())
    {
        Expect.Call(database.InsertFeedDetails(rssFeed.Channels[0])).Return(channelID);
        Expect.Call(database.InsertFeedItem(channelID, rssFeed.Channels[0].Items[0])).Return(1);
        Expect.Call(database.InsertFeedItem(channelID, rssFeed.Channels[0].Items[1])).Return(2);
    }

    using (mocks.Playback())
    {
        bool result = DatabaseManager.SaveFeed(rssFeed);
        Assert.IsTrue(result);
    }
}

Now our DatabaseManager is setup correctly with the methods we want to expose to the public which meet the requirements, we can move onto implementing our IDataSource which will actually store the information.  For this, we are using SubSonic to save all of our Rss information into the database.

The first problem we face is converting our Rss.Net objects into the ActiveRecord SubSonic objects for the database, a method is required to covert between the two objects. Inside of SubSonicTests.cs, we have a test to make sure this is done correctly on our dataSource object.

[Test]
public void ConvertFromRssChannelToSubSonicRssChannel()
{
    RssChannel rssChannel = rss.Channels[0];
    //Returns a SubSonic object.
    MockSubSonic.DAL.RssChannel subSonicChannelObject = dataSource.ConvertRssChannelObject(rssChannel);

    Assert.AreEqual(rssChannel.Title, subSonicChannelObject.Title);
    Assert.AreEqual(TestHelper.url, rssChannel.Link.AbsoluteUri);
    Assert.AreEqual(rssChannel.Link.AbsoluteUri, subSonicChannelObject.Uri);
    Assert.AreEqual(rssChannel.Description, subSonicChannelObject.Description);
    Assert.AreEqual(rssChannel.PubDate, subSonicChannelObject.PubDate);
    Assert.IsTrue(subSonicChannelObject.IsNew); //it shouldn’t save it.
}

We can then implement our solution to save the details into the database, first the details:

[Test]
public void InsertRssChannelIntoDatabase()
{
    int channelId = dataSource.InsertFeedDetails(rss.Channels[0]);
    Assert.AreEqual(channelId, 1);
}

Then the RssItems.

[Test]
public void InsertRssItemIntoDatabase()
{
    int channelId = dataSource.InsertFeedDetails(rss.Channels[0]);
    Assert.GreaterEqualThan(channelId, 0);

    int itemId = dataSource.InsertFeedItem(channelId, rss.Channels[0].Items[0]);
    Assert.AreEqual(itemId, 1);
}

We are not using mock objects at this point because we have refactored to the lowest reasonable point.  Any more and it gets too confusing and becomes pointless. We have cut a lot of the database access out by making it mockable in the first place, having these methods hit the database isn’t going to be a great problem.  So we don’t get any problems in the future, we need to make sure we clean up after ourselves.

[SetUp]
public void TestSetup()
{
    rss = TestHelper.CreateMockRSS(TestHelper.url);
    dataSource = new SubSonicDataStore();
    ExecuteSql(“TRUNCATE TABLE RssChannel”);
    ExecuteSql(“TRUNCATE TABLE RssItem”);
}

[TearDown]
public void TestTearDown()
{
    rss = null;
    dataSource = null;
    ExecuteSql(“TRUNCATE TABLE RssChannel”);
    ExecuteSql(“TRUNCATE TABLE RssItem”);
}

This is the bases for the rest of the implementation of the database.  We use SubSonic within the DataSource without any tricks or mock objects to ensure its working correctly, however in any later which isn’t interacting directly with the database, we are using mock objects.  The other part of the system which I will cover is getting information from the database.

The test below is to ensure that our DataManager object can return RssItems for a Channel based on the ChannelID.

[Test]
public void GetFeedItemsForChannelFromDatabase()
{
    int channelId = 1;
    using (mocks.Record())
    {
        Expect.Call(database.GetRssItemsForChannel(channelId)).Return(rssFeed.Channels[0].Items);
    }

    using (mocks.Playback())
    {
        RssItemCollection rssFeeds = DatabaseManager.GetRssFeedsForChannel(channelId);
        Assert.IsNotNull(rssFeeds);
        Assert.AreEqual(2, rssFeeds.Count);
    }
}

The SubSonic test for this requirement is below.  To start with we are inserting the channel and two feeds from our mock object into the database so we can actually return something.  We then obtain the collection from our database and to ensure all the feeds we got are correct we are verifying them within a foreach loop against our known TestHelper Rss Mock object which we inserted.

[Test]
public void GetRssChannelFeeds()
{
    int channelId = dataSource.InsertFeedDetails(rss.Channels[0]);
    dataSource.InsertFeedItem(channelId, rss.Channels[0].Items[0]);
    dataSource.InsertFeedItem(channelId, rss.Channels[0].Items[1]);

    RssItemCollection rssColl = dataSource.GetRssItemsForChannel(channelId);
    Assert.AreEqual(2, rssColl.Count);

    int i = 0;
    foreach (RssItem item in rssColl)
    {
        Assert.AreEqual(rss.Channels[0].Items[i].Title, item.Title);
        Assert.AreEqual(rss.Channels[0].Items[i].PubDate.ToString(), item.PubDate.ToString());
        Assert.AreEqual(rss.Channels[0].Items[i].Link.AbsoluteUri, item.Link.AbsoluteUri);
        Assert.AreEqual(rss.Channels[0].Items[i].Description, item.Description);
        Assert.AreEqual(rss.Channels[0].Items[i].Author, item.Author);
        i++;
    }
}

The advantage to inserting all the information at the start of the test is that we know what is in the database and what to expect when its returned.  If we relied on the contents of the database, then other tests could change the values or someone could come along and clean out the database – our tests would then fail as what we expected wasn’t what was actually their. This makes debugging the failure even more difficult as we have to investigate why it failed as it might not be because of our implementation but conflicting test runs.

If your interested in how the rest of the system is implemented, please download the project solution at the bottom of the post.

Passing Tests

After we have implemented our API, we have a number of tests which should all pass green.

MockSubSonicPassing

MockSubSonicCoverage

The reason we haven’t got 100% code coverage is because one or two lines of error handling I inserted which wasn’t tested against (for example, if a user couldn’t be found).  In a real system, we would need to test against these situations.  I have exclude the code generated by SubSonic and the RSS.Net project from the report, as that’s not directly related to the system and doesn’t provide a good indication of our unit test coverage.

To actually make sure it all works correctly, I created a simple Console Application which calls all the methods.

static void Main(string[] args)
{
    Console.WriteLine(“Welcome UserA to MockSubSonic”);
    User u = new User(“UserA”, “PassA”, “[email protected]”);
    DatabaseManager.SaveUser(u);

    Console.WriteLine(“Saving Feed”);
    DatabaseManager.SaveFeed(RssFeed.Read(“
http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml”));

    Console.WriteLine(“Subscribing”);
    bool result = DatabaseManager.SubscribeUserToFeed(u.Name, “
http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml”);

    if(result)
        Console.WriteLine(“You successfully subscribed to
http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml”);
    else
        Console.WriteLine(“You failed to subscribed to
http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml. Sorry”);

    RssFeedCollection feeds = DatabaseManager.GetUsersRssFeedCollection(u.Name);
    Console.WriteLine(“You are now subscribed to: ” + feeds.Count);
    Console.WriteLine(“First one is : ” + feeds[0].Channels[0]);

    Console.ReadLine();
}

image

Another way of doing this would have been a more Integrated style test using MbUnit.  It’s the kind of the same as the tests we have wrote before, however it touches more/all parts of the system to verify it is working correctly together.

Summary

I hope you have found this post useful and interesting if you are looking at SubSonic and mock objects.  The important thing to remember when mocking SubSonic is to wrap the SubSonic object inside your own access layer (in this case SubSonicDataStore : IDataStore).

Feedback/comments welcome!

Resources:

Code – Unit Tests, API, Application, SQL zip

SubSonic

Rhino Mocks

MbUnit

Rss.Net

Technorati Tags: , , , ,

How To Unit Test – Using SubSonic

In my previous article I wrote about how to unit test with the database.  However, SubSonic can do all of that work for us.  If you haven’t used it before, SubSonic is a great Object Relational Mapping Framework based on ActiveRecord (same as Ruby on Rails) for .Net 2.0. Simply point it at a database and it will create your all the code for connecting to your database. But once you have this code, how can you test with it?

However, just because SubSonic is a nature and well tested framework it doesn’t mean that you can trust the code it creates as it still needs to be tested.  But don’t expect 100% code coverage!  You will still want to test that the parts of subsonic you are using are actually working correctly. You shouldn’t find any errors, but you ever known!

Scenario

In this post I’m going to create a simple application to insert customers into our database via a console application and also have a list of customers printed out to the console. Similar to the previous post.

The application will be separated into three parts. SubSonic will be used for all the database access, a middle layer will be the ‘glue’ and perform validation on the input (this could be business rules) and will sit on top of subsonic classes.  This will then be accessible from the console application (but it shouldn’t take much to change this to a WinForm/WebForm application).  I know it’s simple (and a bit uninteresting) but I just want to demonstrate the concepts more than anything else.

Unit Tests

The first thing to do is create the database and generate the classes for the database.  I spoke about how to setup SubSonic in a previous post.

Next, I want to be able to insert a customer.

[Test]
public void CreateCustomer()
{
    string name = “John Smith”;
    string email = “[email protected]”;
    Customer c = CustomerManager.CreateCustomer(name, email);
    Assert.AreEqual(name, c.Name);
    Assert.AreEqual(email, c.Email);
}

Here, I have created a CustomerManager static class to provider a layer above the SubSonic implementation. 

I then return a SubSonic generated Customer object.  This is actually really bad as we are returning an object of type ActiveRecord with a lot of additional methods which we wouldn’t want other layers to access (like .Save()).  By doing this, we also need to reference the SubSonic assembly within our test framework, again this is really bad if you want a good separation of the system as we have become dependent on SubSonic.  To stop this, i’m actually going to return our own Customer object to high-layers with just the information we want to expose, we lose some of the advantages of SubSonic but I can accept that for the abstraction. For the moment, it will be just Name and Email.

[Test]
public void CreateCustomer()
{
    string name =  “Customer Test”;
    string email = “[email protected]”;
    Customer c = new Customer(name, email);
    Assert.AreEqual(name, c.Name);
    Assert.AreEqual(email, c.Email);
}

Our CustomerManager implementation then looks like this:

public static Customer CreateCustomer(string name, string email)
{
    HowToUnitTestDB.Customer c = new HowToUnitTestDB.Customer();
    c.Name = name;
    c.Email = email;
    c.Save();

    return new Customer(c.Name, c.Email);
}

Here we are creating two objects, but I feel a lot more conformable with this level of expose and flexibility. If we change to Linq to SQL tomorrow, our higher layers won’t care.

Back to the Tests.  Next, I want to ensure that CustomerManager does correct validation on the fields to ensure no bad data is entering our system.

[Test]
[ExpectedException(typeof(Exception))]
public void CreateNullCustomer()
{
    Customer c = CustomerManager.CreateCustomer(null, null);
    Assert.Fail(“Should not get here”);
}

That’s OK, but we are relying on SubSonic doing the validation, hence why we are expecting a System.Exception to be thrown.  Personally, I would prefer a ArgumentNullException to be thrown instead and I would also prefer CustomerManager to be doing the validation.

[Test]
[ExpectedArgumentNullException]
public void CreateNullCustomerWithOutValidation()
{
     Customer c = CustomerManager.CreateCustomer(null, null);
     Assert.Fail(“Should not get here”);
}

That feels better, notice how i’m using a cool MbUnit attribute to save a little bit of typing and make it more readable.

Next, I want to be able to return a Customer from the database based on their name. If the customer does not exist, I want an ArgumentException to be thrown.  I’m using MbUnit RowTest feature – Read more on this here.

[RowTest]
[Row(“John Smith”)]
[Row(“Unknown Customer”, ExpectedException = typeof(ArgumentException))]
public void GetCustomer(string name)
{
    CustomerManager.CreateCustomerWithoutValidation(“John Smith”, “”);
    Customer c = CustomerManager.GetCustomer(name);
    Assert.AreEqual(name, c.Name);
}

Now I can return one customer, I want to be able to return all the customers as a list.

[Test]
public void GetAllCustomers()
{
    string name = “John Smith”;
    CustomerManager.CreateCustomerWithoutValidation(name + ” A”, “”);
    CustomerManager.CreateCustomerWithoutValidation(name + ” B”, “”);
    CustomerManager.CreateCustomerWithoutValidation(name + ” C”, “”);
    List customers = CustomerManager.GetAllCustomers();
    Assert.AreEqual(3, customers.Count);
}

With the implementation looking like this:

public static List GetAllCustomers()
{
    SqlDataReader dr = (SqlDataReader)HowToUnitTestDB.Customer.FetchAll();

    List custs = new List();

    while (dr.Read())
    {
        Customer c = new Customer();
        c.Name = dr.GetString(1);
        c.Email = dr.GetString(2);
        custs.Add(c);
    }

    return custs;
}

While this test looks fine it does expose a problem with the tests as a whole and that is that we are not cleaning up after ourselves, like with the last post.  This is one of the problems with database testing as you need to ensure the tests don’t leave lasting data which can have knock on effects.

Executing the test, we receive this error message.

Error    1    TestCase ‘CustomerManagerTests.GetAllCustomers’ failed:  Equal assertion failed: [[3]]!=[[47]]
MbUnit.Core.Exceptions.NotEqualAssertionException
Message:  Equal assertion failed: [[3]]!=[[47]]
Source: MbUnit.Framework
StackTrace:
   at MbUnit.Framework.Assert.FailNotEquals(Object expected, Object actual, String format, Object[] args)
   at MbUnit.Framework.Assert.AreEqual(Int32 expected, Int32 actual, String message)
   at MbUnit.Framework.Assert.AreEqual(Int32 expected, Int32 actual)
   at SubSonic.Tests.CustomerManagerTests.GetAllCustomers() in E:UsersBen HallDocumentsVisual Studio 2008ProjectsHowToUnitTestSubSonic.TestsCustomerManagerTests.cs:line 69    E:UsersBen HallDocumentsVisual Studio 2008ProjectsHowToUnitTestSubSonic.TestsCustomerManagerTests.cs    69
   

To solve this, I will use the SetUp and TearDown fixtures, however I don’t really want a method to delete the customers on my CustomerManager ( CustomerManager.DeleteAllCustomers();) just to be able to clean up my test code.

[SetUp]
public void TestSetup()
{
    DeleteCustomers();
}

[TearDown]
public void TestTearDown()
{
    DeleteCustomers();
}

private static void DeleteCustomers()
{
    SqlConnection sqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings[“DatabaseConnection”].ConnectionString);
    SqlCommand sqlCmd = new SqlCommand(“TRUNCATE TABLE dbo.Customer”, sqlConn);

    try
    {
        sqlConn.Open();

        sqlCmd.ExecuteNonQuery();
    }
    finally
    {
        if (sqlConn.State == System.Data.ConnectionState.Open)
            sqlConn.Close();
    }
}

This is a bit naughty as we are accessing the database directly, however I feel it is the better of two evils in this situation, the more complex your data becomes maybe you would rethink, or if you already had a DeleteAllCustomers() method you could use that,  it’s just that in this case at the moment we don’t.

Hopefully by now your getting a good feel for unit testing with SubSonic, sadly we don’t mock anything but it doesn’t mean you can’t do it…  One final thing I want to talk about is verifying updates to a customer.

To update a customer, we need to know their ID.  At the moment, our public customer object doesn’t expose this information, however we can quickly modify this.

[Test]
public void GetCustomerID()
{
    string name = “John Smith”;
    CustomerManager.CreateCustomerWithoutValidation(name, “”);

    Customer c = CustomerManager.GetCustomer(name);

    Assert.AreEqual(1, c.ID);
}

In order for this to build, I need to add a ID property on the Customer object

public int ID { get; internal set; }

I can then modify my GetCustomer method to return the ID as well. All my previous tests ensure I haven’t broken anything along the way.  We can now write a correct test.

[Test]
public void UpdateCustomer()
{
    string name = “John Smith”;
    CustomerManager.CreateCustomerWithoutValidation(name, “”);
    Customer c = CustomerManager.GetCustomer(name);
    Assert.AreEqual(name, c.Name);

    c.Email = “[email protected]”;

    CustomerManager.UpdateCustomer(c.ID, c);
}

After that, the passing implementation looks like this:

public static void UpdateCustomer(int customerID, Customer c)
{
    HowToUnitTestDB.Customer dbCust = HowToUnitTestDB.Customer.FetchByID(customerID);
    dbCust.Name = c.Name;
    dbCust.Email = c.Email;
    dbCust.Save();
}

We can now insert, get and update customers.  Great! We just need to put a UI on it.  A simple console application will do:

class Program
{
        [STAThread]
        public static void Main(string[] args)
        {
            Console.WriteLine(“How To Unit Test: SubSonci”);
            string command = GetCommand();

            while (command != “Quit”)
            {
                switch (command)
                {
                    case “Insert”:
                        InsertCustomer();
                        break;
                    case “Get”:
                        GetCustomer();
                        break;
                    case “Update”:
                        UpdateCustomer();
                        break;
                    default:
                        break;
                }

                command = GetCommand();
            }
        }
}

…. The code is sightly too long to post here (download the solution at the end), but the InsertCustomer looks like this:

private static void InsertCustomer()
{
    Console.WriteLine(“Enter new customer details”);
    Console.WriteLine(“Name:”);
    string name = Console.ReadLine();
    Console.WriteLine(“Email:”);
    string email = Console.ReadLine();
    CustomerManager.CreateCustomer(name, email);
    Console.WriteLine(“Saved”);
}

Summary

In summary, you can unit test against subsonic, but it involves hitting with the database. I hope you have found this of some use and provided you with a good insight.  In a later post I will discuss how we can mock SubSonic (Hopefully). 

SubSonic can be found at http://www.codeplex.com/actionpack

Download Solution: HowToUnitTestSubSonic.zip

Technorati Tags: , , ,

How To Unit Test – Interacting with the Database

One of the problems I have found with unit testing is there are a lot of people writing about the theory of TDD and Unit Testing and a lot of people writing about how to do simple Unit Testings (Assert.Equals(accountA.Balance, accountC.Balance).  But not so many people are talking about how to actually unit test real world objects and scenarios (or they are and i’m just completely missing them).  Over a series of blog posts, I hope to change that 🙂 All the posts will be tagged with MbUnit, TDD and Testing if you want to follow them easily.

In this first post, I will discuss unit testing with code which involves interacting with a database.  People have spoken about this before, but it is the most common scenario so I thought I would start here.  I have already wrote about mocking a database in Part 2 of my Rhino Mocks series on ASP Alliance. In this post, I will focus on unit testing and interacting directly with the database.

Why would you not want to interact with the database?

I thought I would start with saying why interacting with a database isn’t recommend during unit tests.  The main reason is because a unit should be a single, isolated block of code with no dependencies on other parts of the application.  Having a database breaks this as you need to ensure that the database is setup, populated and accessible at runtime (think from build servers).  By mocking out the database, we remove this dependency and our tests become more encapsulate and easier to maintain.

Another problem is that database tests are slow.  For every test you need to setup data, perform queries and tear down data, it all takes time and effort and distracts from the intent of the test. If you are running your tests every time you build, then this additional overhead definitely makes the process more painful.

Finally, if you use a central server to execute the tests against, you might have problems if other developers or testers are also testing the tests at the same time.

However, as I mentioned in the article, while mocking out the database is great when your testing your higher layers (API/Business Logic) you still have to test your actual data access against a database – otherwise how else will you know it works?  Most people refer to this as a integration test instead of a unit test as its breaking the machine boundary.

Scenario

For this sample, I will create a Customer Database where we can insert, update and delete Customer records.  Very simple application, but we have all had a similar requirement.  I’ll write the test code inline to demonstrate my thought process, if you want to know how I actually implemented the solution then the solution is downloadable at the end.

TDD/Unit Tests

The first thing we want to do is be able to do is connect to the database using a connection string from the configuration file.  For this, we need to obtain the connection string from the App.Config.

[Test]
public void GetConnStringFromAppConfig()
{
     DataAccess da = new DataAccess();
     string actualString = da.ConnectionString;
     string expectedString = System.Configuration.ConfigurationManager.ConnectionStrings[“DatabaseConnection”].ConnectionString;
     Assert.AreEqual(expectedString, actualString);
}

This is a test just to make sure that when we construct the DataAccess layer, the connection string property is populated correctly.  Once we have a passing test, we can move on.

The next thing we need to be able to do is be able to connect and disconnect from the database.

[Test]
public void ConnectAndDisconnectFromDatabase()
{
    DataAccess da = new DataAccess();

    bool connected = da.Connect();

    bool disconnected = da.Disconnect();

    Assert.IsTrue(connected);

    Assert.IsTrue(disconnected);
}

While this test does touch two different items, its important to disconnect from the database during the test so we might as well test both items. When executing this test, it fails due to a problem logging in to the database.  As all this does it try to connet to the database, we know its either because the server is down, your login credentials are wrong or the database doesn’t exist. As we know the server is up and we are using integration security it must be the database. For this solution I have created a database called HowToUnitTest and using Integrated Security as the login mode.

Next we need a way to actually execute tests on the server. For this I’m going to have a method which returns a SqlCommand which can execute a stored procedure.

[Test]
public void GetSqlCommand()
{
    string spoName = “spoTest”;
    DataAccess da = new DataAccess();
    SqlCommand response = da.GetSqlCommand(spoName);

    Assert.IsNotNull(response);
    Assert.AreEqual(spoName, response.CommandText);
}

This method will only be used internally and other methods will be accessible on the DataAcccess object to execute the SqlCommand.  That can be our next test.

[Test]
public void ExecuteSqlCommand()
{
    string spoName = “sp_who2”;
    DataAccess da = new DataAccess();
    SqlCommand response = da.GetSqlCommand(spoName);
    da.Connect();
    DataTable ds = da.ExecuteSqlCommand(response);

    da.Disconnect();
    Assert.IsTrue(ds.Rows.Count > 0);
}

Great!, we have a set of tests to execute a command on the database (even if all it does is return who is logged in). Now, lets actually do something involving data!  I want to be able to insert a customer into the database.

[Test]
public void InsertCustomerIntoDatabase()
{
    string spoName = “InsertCustomer”;
    DataAccess da = new DataAccess();
    da.Connect();
    SqlCommand response = da.GetSqlCommand(spoName);
    response.Parameters.Add(“Name”, SqlDbType.NVarChar).Value = “Customer Test 1”;
    response.Parameters.Add(“Email”, SqlDbType.NVarChar).Value = “[email protected]”;

    int rows = response.ExecuteNonQuery();
    Assert.AreEqual(1, rows);
}

This command will call InsertCustomer with Name and Email as a parameter.  However, this isn’t a great way to do it as it involves our calling code doing a lot of the leg work some i’m going to refactor the code to be a little bit easier to understand.  First, we need a customer object.

[TestFixture]
class CustomerTests
{
    [Test]
    public void CreateCustomer()
    {
        string name =  “Customer Test”;
        string email = “[email protected]”;
        Customer c = new Customer(name, email);
        Assert.AreEqual(name, c.Name);
        Assert.AreEqual(email, c.Email);
    }
}

Next, we want to call a method on the DataAccess to insert the customer which returns true if it inserted correctly.

[Test]
public void InsertCustomerIntoDatabase()
{
    string name = “Customer Test”;
    string email = “[email protected]”;

    DataAccess da = new DataAccess();
    bool inserted = da.InsertCustomer(new Customer(name, email));
    Assert.IsTrue(inserted);
}

This is great, we have changed our code to make more sense.  Now we have a customer object, we can do a lot more based on this.  For example, we could Delete a Customer or Update a Customer just by creating and calling the method on the data access object.  The problem with implementing those methods is that first we need some way to get a customer out of the database.  So let’s write a test for that.

[Test]
public void GetCustomer()
{
    string name = “Customer Test”;

    DataAccess da = new DataAccess();
    da.Connect();

    Customer c = da.GetCustomer(name);

    da.Disconnect();

    Assert.IsNotNull(c);
    Assert.AreEqual(name, c.Name);
    StringAssert.IsNonEmpty(c.Email);
}

Now we can get customers from the database, we can update customers.

[Test]
public void UpdateCustomer()
{
    string name = “Customer Test”;
    string updatedName = “Updated Customer”;
    DataAccess da = new DataAccess();
    da.Connect();

    Customer c = da.GetCustomer(name);

    c.Name = updatedName;
    da.UpdateCustomer(c);

    Customer c2 = da.GetCustomer(updatedName);

    da.Disconnect();

    Assert.AreEqual(updatedName, c2.Name);
    Assert.AreEqual(c.Email, c2.Email);
}

In this test, we are getting a customer, updating their name, requerying for the customer again and asserting that the details are correct.  This test looks fine, the first time we run the test it passes, however the next it cannot find the “Customer Test” customer and fails.  This is because that customer is no longer in our database, it is “Updated Customer”, we have created dependencies within our tests! Not great as we cannot easily isolated the tests from each other and tests cannot be run independently of each other.  What we really need to do is have a known state for the database before we start and clean up after ourselves once we finish.

MbUnit has a cool attribute called [Rollback] which wraps the test inside of a transaction and once it has finished, automatically rolls it back.  This solves our problem of needing to clean up after ourselves as MbUnit can do it for us. Just add the attribute under [Test] and the framework will do the rest for you.

The only problem then is having a known good state for the database.

Our UpdateCustomer test now looks like this:

[Test]
[RollBack]
public void UpdateCustomer()
{
    string name = “Customer Test”;
    string updatedName = “Updated Customer”;
    DataAccess da = new DataAccess();
    da.Connect();

    da.InsertCustomer(new Customer(name, “[email protected]”));

    Customer c = da.GetCustomer(name);

    c.Name = updatedName;
    da.UpdateCustomer(c);

    Customer c2 = da.GetCustomer(updatedName);

    da.Disconnect();

    Assert.AreEqual(updatedName, c2.Name);
    Assert.AreEqual(c.Email, c2.Email);
}

We insert a known customer in the database, and then try and return it.  InsertCustomer is being tested by another test so if that has a problem, the other test will fail as well to make debugging easier.  Next, we want to delete a customer.

[Test]
[RollBack]
public void DeleteCustomer()
{
    string name = “Customer Test”;
    string email = “[email protected]”;
    DataAccess da = new DataAccess();
    da.Connect();

    da.InsertCustomer(new Customer(name, email));

    Customer c = da.GetCustomer(name);

    da.DeleteCustomer(c);

    Customer c2 = da.GetCustomer(name);

    da.Disconnect();

    Assert.IsNull(c2);
}

You may notice that we have said that if a customer doesn’t exist, it should return null however, we haven’t got a test for this so lets write one.

[Test]
public void IfCustomerNotFoundReturnNull()
{
    da.Connect();
    Customer c = da.GetCustomer(“Unknown”);
    da.Disconnect();
    Assert.IsNull(c);
}

We don’t need a rollback attribute as we are not making any changes to the database. The only method left now is to return all the customers from the database.

[Test]
[RollBack]
public void GetAllCustomers()
{
    string name = “Customer Test”;
    string email = “[email protected]”;
    int insertCount = 5;

    DataAccess da = new DataAccess();
    da.Connect();

    for (int i = 0; i < insertCount; i++)
    {
        da.InsertCustomer(new Customer(name + i, email));

    }

    List customers = da.GetAllCustomers();

    da.Disconnect();

    Assert.IsNotNull(customers);
    Assert.IsTrue(customers.Count == insertCount);
}

One thing left to do is add a TestCategoryAttribute to all the tests to say they are Database related. By using TestCategory, we can target which tests you want to run.  If you know your integration server doesn’t have access to a database then you can setup the tests to run all but the Database category.  This way, the tests aren’t executed and the failing tests are because of a problem and not database errors.  This is also really useful if you know you quickly want to execute your tests and are sure the database code hasn’t changed. 

We now have a set of passing tests for our DataAccess object, however there is a lot of repeating code within our database tests which could be removed. By using the Setup and Teardown we can remove a lot of this duplicated code and make our tests more readable.

DataAccess da = null;

[SetUp]
public void TestSetup()
{
    da = new DataAccess();
}

[TearDown]
public void TearDown()
{
    da = null;
}

That is now requirement complete.  Some refactoring on the internals of the actual code should be performed but now we have a full suite of tests we can easily perform this would fear of breaking anything.

One thing I haven’t coded yet is validation. This should also be tested.

[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void IfCustomerNameNullThrowArgumentException()
{
    string name = null;
    string email = “[email protected]”;

    Customer c = new Customer(name, email);

    Assert.Fail(“If we get here, an exception hasn’t been thrown”);
}

When it comes to writing high level tests, we have two choices. We can either mock out the DataAccess object as that has been fully tested and is what I would recommend, or we can simply write more tests like GetAllCustomers() which insert all the data into the database, do some processing, and assert the response cleaning up after itself. However, as mentioned at the beginning we are already stretching the definition of unit when testing and creating the Data Access so API/BI tests interacting with the database is definitely not advised.

Download Sample

Download the solution, including the tests and the implementation code.

http://blog.benhall.me.uk/Code/HowToUnitTest/HowToUnitTest_Databases1.zip

In summary, I hope you have found this post useful. I hope you can see what we are aiming from when writing tests and how we can go about keeping them small and isolated but still interacting with a database.  If we were using mocks, we would mock out the SqlCommand section which actually executed the tests against the database and replace this with our own internal code. See my article for more on this. 

Any feedback on this post would be most welcome, if you want me to write how to unit test anything, then please let me know.

Technorati Tags: , ,

assembly:InternalsVisibleToAttribute – Test Internal Methods

One of the problems with unit testing is that you can only test public accessible items within the assembly.  To solve this you have to make more items visible and increase your public interface in order to be able to unit test the item.  This is bad if you are planning on making your API useable outside of your own system as changing the public interface could cause breaking changes in other peoples’ systems.  It also means your internal system is exposed and useable to anyone.

The InternalsVisibleTo attribute solves this problem.  By including this within your AssemblyInfo.cs you can set which assemblies can access you internal items.  This means you can test your assembly without having to set everything to public.  You even get intellisense support with all of your internal methods listed.

If we have an assembly MyAPI which is tested by MyAPI.Tests.  If in our MyAPI.class we have the following code

public class MyPublicClass
{
    public bool IsValid()
    {
        return true;
    }

    private bool AllowedAction(string action)
    {
        if (string.IsNullOrEmpty(action))
            return false;

        return true;
    }
}

Which has the following test

[TestFixture]
public class MyPublicClassTests
{
    [Test]
    public void TestIsValid()
    {
        MyPublicClass cls = new MyPublicClass();
        Assert.IsTrue(cls.IsValid());
    }
}

In order for us to test the AllowedAction method we would have to make it public.  But then everyone using the API would be able to use it and we would be unable to refractor this method for the lifetime of the API.  By adding the attribute to the MyAPI.AssemblyInfo file and change the method from private to internal.

[assembly: InternalsVisibleTo(“MyAPI.Tests”)]

internal bool AllowedAction(string action)
{
    if (string.IsNullOrEmpty(action))
        return false;

    return true;
}

[Test]
public void TestActionAllowed()
{
    MyPublicClass cls = new MyPublicClass();
    Assert.IsTrue(cls.AllowedAction(“Test”));
}

This is great, we have only increased our public interface to our test method yet all the other assemblies cannot access it.  However, one problem with this is that if another malicious user came along with an assembly called MyAPI.Tests then they also would be able to access the internal actions.

Then is why it is recommend to sign the test assembly and include the public key within the attribute. In order to obtain the public key, you need to run the sn application on the assembly.

sn -Tp MyAPI.Tests.dll

The attribute would then look like this.

[assembly: InternalsVisibleTo(“MyAPI.Tests,PublicKey=00240000048…………de35d15ffae”)]

However, it means MyAPI must have a strong name/be signed.

An example of this being used is with the System.Data.Linq assembly, you can see that Microsoft use this attribute to allow the assembly to be tested by another assembly called DLinq.Unittests.

[assembly:InternalsVisibleTo(“DLinq.Unittests,PublicKey=########”)]

MSDN Link – http://msdn2.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

Technorati Tags: , ,