Click here to Skip to main content
6,822,613 members and growing! (17,057 online)
Email Password   helpLost your password?
Development Lifecycle » Testing and QA » General     Intermediate License: The Code Project Open License (CPOL)

Unit Testing and Integration Testing in business applications

By Omar Al Zabir

I will show you some realistic unit and integration test examples in a N-tier web application, which should help you write tests that gives you confidence and helps you gradually move towards TDD
C#, .NET, ASP.NET, LINQ, Architect, Dev, QA
Revision:5 (See All)
Posted:20 Nov 2009
Updated:24 Nov 2009
Views:7,190
Bookmarked:49 times
Unedited contribution
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
17 votes for this article.
Popularity: 5.78 Rating: 4.70 out of 5

1

2
2 votes, 11.8%
3

4
15 votes, 88.2%
5

Introduction

I am yet to find a proper sample on how to do realistic Test Driven Development (TDD) and how to write proper unit tests for complex business applications, that gives you enough confidence to stop doing manual tests anymore. Generally the samples show you how to test a Stack or a LinkedList, which is far simpler than testing a typical N-tier application, especially if you are using Entity Framework or Linq to SQL or some ORM in data access layer, and doing logging, validation, caching, error handling at middle tier. There are many articles, blog posts, video tutorials on how to write unit tests, which I believe are all very good starting points. But all these examples show you basic tests, not good enough to let your QA team go. So, let me try to show you some realistic unit and integration test examples which should help you write tests that gives you confidence and helps you gradually move towards TDD.   

Background

I will show you tests done on my open source project Dropthings, which is a Web 2.0 AJAX portal built using jQuery, ASP.NET 3.5, Linq to SQL, Dependency Injection using Unity, caching using Microsoft Enterprise Library, Velocity and so on. Basically all the hot techs you can grasp in one shot. The project is a typical N-tier application where there’s a web layer, a business layer and a data access layer. Writing unit tests, integration tests and load tests for this project was challenging, and thus interesting to share so that you can see how you can implement Unit Testing and Integration Testing in a real project and gradually get into Test Driven Development.

Those who are uninitiated to unit testing, integration testing, test driven development etc, some quick introduction:

  • Unit testing is a way to write code to test unit of code, say a class. You write test methods, which tests a certain Class’s certain method (a unit). For example, you write code to ensure Stack’s Pop method returns the last pushed item. In unit test, you test only one class at a time. If the class you are testing is dependent on some other class, then that class is stubbed or mocked (dummy implementation). For example, say you are testing a class that uses File. When you unit test that class, you will use a DummyFile to eliminate the need for a physical file system. Thus unit test tests the logic of the class that’s under test, not anything else. The way to make you classes switch from real implementation to dummy/stub implementation is by using interfaces, not the real class. So, your classes should use IFile or IDatabase instead of using File and Database directly. There are many articles, blog posts, video tutorials on how to write unit tests. One principle to remember during unit test is, when you are unit testing a class, you should have no dependency on database, file, registry, web services, etc. You should be able to test any class in complete “isolation” and your classes should be designed to support complete “isolation”.
  • Integration testing tests a class while it is integrated with other classes. For example, you are testing CustomerData, which depends on Linq to SQL and a database connection. In integration test, you test CustomerData’s methods by calling them and ensuring it does its job properly engaging all the related classes. Integration test is more popular among developers since it gives more confidence that the integration test is really testing the system as it should be.
  • Test Driven Development (TDD) is an extreme form of unit testing. The principle is you write unit test first, and then you write the actual code. For example, first you write unit test which tests CustomerData class. But there’s no real code in CustomerData class in the beginning. CustomerData class contains functions like InsertCustomer, DeleteCustomer, GetCustomer etc, which does no real job but retuning some dummy Customer objects to satisfy the unit test. Once the unit tests are all passing against the dummy data, then you start writing the real code inside CustomerData’s methods, where you make it talk to database and do the real stuff. After writing the real code, your unit tests should pass without requiring any change in the test code. This is called Test Driven Development. TDD also requires you to design your classes in such a way that no class depends on some other class directly. All the dependencies are via interfaces. For example, CustomerData does not use SqlConnection directly, instead it uses ISqlConnection. All the dependencies are given to CustomerData via its constructor.

Test Driven Development is a hard topic. It takes time to get your head around it because it proposes some specific design and development approach so that your code becomes unit testable and you can write test first and then write the actual implementation. The benefit of doing TDD is, whatever code you produce, there’s automated test already there to test the code. Moreover, you design your classes based on how they are used by writing the test code first and then writing the class.

Testing using Behavior Driven Development

I have some preference how I write tests. I find the traditional way of writing unit tests insufficient. In pure unit tests, you write one test method to test one and only one method of some class and there’s one Assert method to test only one expectation at a time. For example, if you are testing Stack’s Pop method, a single unit test method should only test one expectation on the Pop method. For example, Pop should return you the last pushed item. So, if you are writing a traditional unit test method, you will write:

[Test] 
public void Pop_Should_Return_The_Last_Pushed_Item() 
{ 
  Stack stack = new Stack(); 
  stack.Push(1); 
  Assert.Equal(1, stack.Pop()); 
} 

However, testing a single method for a single expectation is cumbersome. You have to write way too many test methods to test a certain method’s overall behavior. Moreover in every test method you have to setup the class under test with proper context and then call the method you want to test just to verify one specific expectation. So, I find Behavior Driven Development (BDD) style more useful than traditional way of doing - “one function and one assert per test method” style TDD. I also use xUnit because I think this is the most pragmatic one out there compared to NUnit, mbUnit. Here you will see how I do unit test using xUnit and Subspec, which an extension of xUnit.

Before we begin, some background on Behavior Driven Development. In this practice, components are tested against their expected “Behavior”. And a behavior is defined in this form:

Given some initial context (the givens),
When an event occurs,
then ensure some outcomes.

For example,

Given an empty Stack
When an item is pushed into the stack and Pop is called
then it returns the last item that’s pushed into the stack
and it removes the item from the stack
and further Pop call throws exception.

Here you define the complete behavior of the Pop method. The test method that tests this behavior ensures all the expected and related behaviors of Pop.

Here I will show you how you can unit test your components against such behaviors. Then I will show you how you can do integration tests against such behavior. Finally, I will show you how to get to Test Driven Development where you write test first and then code.

Unit testing using BDD

First we will unit test the data access layer. Data Access layer deals with object persistence using Linq to SQL. It also does caching at entity level. For example, when you want to load a user, it first checks from cache if the user is already cached, if not, it loads the user from database and then caches it.

Let’s look at PageRepository, which deals with Page entity persistence. It has common CRUD methods. Consider an example GetPageById which takes a PageId and loads that Page from database.

public class PageRepository : IPageRepository
{
    #region Fields
    private readonly IDropthingsDataContext _database;
    private readonly ICache _cacheResolver;
    #endregion Fields

    #region Constructors
    public PageRepository(IDropthingsDataContext database, ICache cacheResolver)
    {
        this._database = database;
        this._cacheResolver = cacheResolver;
    }
    #endregion Constructors

    #region Methods
    public Page GetPageById(int pageId)
    {
        string cacheKey = CacheSetup.CacheKeys.PageId(pageId);
        object cachedPage = _cacheResolver.Get(cacheKey);

        if (null == cachedPage)
        {
            var page = _database.GetSingle<Page, int>(
                   DropthingsDataContext.SubsystemEnum.Page, 
                    pageId, 
                    LinqQueries.CompiledQuery_GetPageById);
            page.Detach();
            _cacheResolver.Add(cacheKey, page);
            return page;
        }
        else
        {
            return cachedPage as Page;
        }
    } 

PageRepository takes IDropthingsDataContext, which is a unit testable Linq to SQL DataContext. By default, Linq to SQL will not generate DataContext that is unit testable. You will have to try Kazi’s method to make a DataContext unit testable. Next, it takes ICache which is an interface that deals with cache. Assume somewhere there’s an implementation of this interface which is providing caching support using say Enterprise Library Caching or Velocity or Memcached. For example, assume there’s some class called EnterpriseLibraryCache which implement ICache.

Let’s test it. We will ensure that:

Given a new PageRepository and empty cache
When GetPageById is called with a PageId
then it checks in the cache first and finds nothing,
and it loads the page from database,
and it returns the page as expected.

The above statement is a behavior.

Let’s code it using xUnit and Subspec:

[Specification]
public void GetPage_Should_Return_A_Page_from_database_when_cache_is_empty_and_then_caches_it()
{
    var cache = new Mock<ICache>();
    var database = new Mock<IDropthingsDataContext>();
    IPageRepository pageRepository = new PageRepository(database.Object, cache.Object);

    const int pageId = 1;
    var page = default(Page);
    var samplePage = new Page() { ID = pageId, Title = "Test Page", ...};

    database
        .Expect<Page>(d => d.GetSingle<Page, int>(
                              DropthingsDataContext.SubsystemEnum.Page,
                               1, LinqQueries.CompiledQuery_GetPageById))
        .Returns(samplePage);

    "Given PageRepository and empty cache".Context(() =>
        {
            // cache is empty
            cache.Expect(c => c.Get(It.IsAny<string>())).Returns(default(object));
            // It will cache the Page object afte loading from database
            cache.Expect(c =>
                 c.Add(It.Is<string>(cacheKey =>
                       cacheKey == CacheSetup.CacheKeys.PageId(pageId)), 
                      It.Is<Page>(cachePage =>
                          object.ReferenceEquals(cachePage, samplePage))))
                .AtMostOnce().Verifiable();
        });

    "when GetPageById is called".Do(() =>
        page = pageRepository.GetPageById(1));

    "it checks in the cache first and finds nothing and then caches it".Assert(() =>
        cache.VerifyAll());

    "it loads the page from database".Assert(() =>
        database.VerifyAll());

    "it returns the page as expected".Assert(() =>
        {
            Assert.Equal<int>(pageId, page.ID);
        });
    
}

First I am setting up the PageRepository. It takes IDropthingsDataContext and ICache. So, I am mocking it using Moq. Then I am setting up a sample Page object which will be used to do the test. Then I am setting an expectation on the database that PageRepository will call GetSingle method to run a specific Linq to SQL query and pass the PageId as 1 in order to retrieve a single Page object. Moreover, I am stubbing the call to database.GetSingle(…) to return samplePage. The great thing about mocking is it saves you from writing dummy classes or stubs for your unit tests and you can not only write stubs but also validate that the stubs are called with the right input and the right output is being produced.

Next I am setting up the context, “Given PageRepository and empty cache”. PageRepository is already there, so I just need to setup an empty cache. I do this by setting expectation that whenever Get is called, it will return null. Thus simulating empty cache. Another expectation is there will be one and only one call to Add method to store the samplePage object that is loaded from database.

Next I call the GetPageById method on PageRepository. Once the call is done, first I test if the expectations set on the cache object, which is that a call to Get function and one and only one call to Add function, have been met or not. This ensures GetPageById is doing the caching as expected.

Following Assert verifies that the expectation on database has been met, which is to query the database to get a single Page object by passing PageId as 1.

Finally, the last Assert checks if the returned page has the same ID as it was asked to return.

This test ensures the expected behavior is satisfied.

What’s the point of doing Unit Test?

At this point, most of you will wonder, why are we writing three times the code to test only couple of lines of straight forward obvious code? If we are stubbing calls to database and cache and PageRepository is doing nothing but calling database and cache, what’s the point of doing the test then when nothing is happening but calling some mocks? If every single implementation detail is already known to the test code, what’s the point writing the test then?

I find writing unit tests pointless when the method under test does nothing but calling some other method which are mocked in the test. The unit test already knows exactly what other class and method will be called and the test mocks all of them. It seems pointless to write code to test such method when everything the method does is mocked. So, to me, writing such unit test is pointless. But if the method under test has some other logic inside it, then unit testing makes sense since the unit test will test the logic inside the method and will ensure the mocks are getting called properly after the logics are applied. In the above example, whether to call cache or database is decided within the method. Thus there’s logic that can be tested. In such case, unit testing makes sense.

If you aren’t still convinced, let me give you example of a scenario where these unit tests will save your life. For example, say you changed the way caching is done at Data Access Layer. For example, I changed my code to use AspectF library. This required changes in the code of PageRepository. After changing the code, I had to ensure the PageRepository is still doing things as per the expected behaviors. No matter what caching approach I use, it should not be changing the caching behavior which is - check in cache to make sure the requested object is not already in cache and then load from database and then cache it. The changed GetPageById method, after implementing AspectF, looks like this:

public Page GetPageById(int pageId)
{
    return AspectF.Define
        .Cache<Page>(_cacheResolver, CacheSetup.CacheKeys.PageId(pageId))
        .Return<Page>(() =>
            _database.GetSingle<Page, int>(DropthingsDataContext.SubsystemEnum.Page,
                pageId, LinqQueries.CompiledQuery_GetPageById).Detach());
}        

Here AspectF is doing nothing but making my caching life easier. Now when I run the unit test, it passes fine.

It confirms that the behavior of PageRepository hasn’t changed, despite the drastic change in its code. It is still doing the same thing as it is expected to do. Thus I can do refactoring, re-engineering without having the fear that I might break something that I will discover too late at the cost of missed deliveries. Having *proper* unit tests always give you the confidence that even if you make drastic changes in the code, as long as your unit tests are all passing, your system is problem free.

Next let’s test when the cache is full does it properly return objects from cache and does it not unnecessarily query the database? The following test will ensure that:

[Specification]
public void GetPage_Should_Return_A_Page_from_cache_when_it_is_already_cached()
{
    var cache = new Mock<ICache>();
    var database = new Mock<IDropthingsDataContext>();
    IPageRepository pageRepository = new PageRepository(database.Object, cache.Object);
    const int pageId = 1;

    var page = default(Page);
    var samplePage = new Page() { ID = pageId, Title = "Test Page",
            ColumnCount = 3, LayoutType = 3, UserId = Guid.Empty, VersionNo = 1,
            PageType = Enumerations.PageTypeEnum.PersonalPage,
            CreatedDate = DateTime.Now };

    "Given PageRepository and the requested page in cache".Context(() =>
    {
        cache.Expect(c => c.Get(CacheSetup.CacheKeys.PageId(samplePage.ID)))
            .Returns(samplePage);
    });

    "when GetPageById is called".Do(() =>
        page = pageRepository.GetPageById(1));            

    "it checks in the cache first and finds the object is in cache".Assert(() => 
    {
        cache.VerifyAll();
    });

    "it returns the page as expected".Assert(() =>
    {
        Assert.Equal<int>(pageId, page.ID);
    });
}

This test is even simpler. The only difference is in the setup of Context where we are setting an expectation that when it’s requesting a specific page from cache, it will return the samplePage object. Mock will throw an exception whenever any function is called for which there’s no expectation set. So, if the code tried to call anything on database object, or anything else on the cache object, it would throw exception. Thus we verify that it’s not doing what it should not do. This ensures we are doing negative test as well.

Integration Testing using BDD

Integration test means you are going to test some class while it is integrated with other classes and with infrastructure like database, file system, mail server etc. So, whenever you are writing integration test, you are testing a components behavior as it should be working without any mocking. Integration tests are easier to write as there’s no mocking. Moreover, it gives you more confidence that your code works as it should be since all the necessary components and dependencies are in place and they are also being tested as part of the test.

Let me show you how I test my Business Facade layer. Business Facade does the orchestration of data access component and all other utility components. It encapsulates user actions into one business operation. For example, on Dropthings, when a brand new user visits for the first time, user gets some default pages and widgets created. These pages and widgets come from a template user. There’s a user named anon_user@dropthings.com, who has the default pages and widgets. That particular user’s pages and widgets are copied to every new user. Since this is a complex operation, it was a good candidate to do automated integration test.

When a user visits the Default.aspx for the first time, the FirstVisitHomePage is called on the Facade. It goes through a complex process to clone the template user’s pages and widgets and setting the right user settings and so on. The integration test will ensure that if the FirstVisitHomePage is called with parameters that identifies a new user visiting the site, then it will return an object model which has the default pages and widgets created for the user. Thus the behavior is:

Given anonymous user who has never visited the site before
when the user visits for the first time
then it creates widgets on the newly created pages at exact columns and
positions as the anon user's pages

public class TestUserVisit
{
  public TestUserVisit()
  {
    Facade.BootStrap();
  }
  /// <summary>
  /// Ensure the first visit produces the pages and widgets defined in the template user
  /// </summary>
  [Specification]
  public void First_visit_should_create_same_pages_and_widgets_as_the_template_user()
  {
    MembershipHelper.UsingNewAnonUser((profile) =>
    {
      using (var facade = new Facade(new AppContext(string.Empty, profile.UserName)))
      {
        UserSetup userVisitModel = null;

        // Load the anonymous user pages and widgets
        string anonUserName = facade.GetUserSettingTemplate()
             .AnonUserSettingTemplate.UserName;
        var anonPages = facade.GetPagesOfUser(facade.GetUserGuidFromUserName(anonUserName));

        "Given anonymous user who has never visited the site before"
           .Context(() => { });

        "when the user visits for the first time".Do(() =>
        {
          userVisitModel = facade.FirstVisitHomePage(profile.UserName,
             string.Empty, true, false);
        });

        "it creates widgets on the newly created page at exact columns and
         positions as the anon user's pages".Assert(() =>
        {
          anonPages.Each(anonPage =>
          {
            var userPage = userVisitModel.UserPages.First(page =>
                    page.Title == anonPage.Title
                    && page.OrderNo == anonPage.OrderNo
                    && page.PageType == anonPage.PageType);

            facade.GetColumnsInPage(anonPage.ID).Each(anonColumn =>
            {
              var userColumns = facade.GetColumnsInPage(userPage.ID);
              var userColumn = userColumns.First(column =>
                      column.ColumnNo == anonColumn.ColumnNo);
              var anonColumnWidgets = 
                facade.GetWidgetInstancesInZoneWithWidget(anonColumn.WidgetZoneId);
              var userColumnWidgets = 
                facade.GetWidgetInstancesInZoneWithWidget(userColumn.WidgetZoneId);
              // Ensure the widgets from the anonymous user template's columns are 
              // in the same column and row.
              anonColumnWidgets.Each(anonWidget =>
                 Assert.True(userColumnWidgets.Where(userWidget =>
                  userWidget.Title == anonWidget.Title
                  && userWidget.Expanded == anonWidget.Expanded
                  && userWidget.State == anonWidget.State
                  && userWidget.Resized == anonWidget.Resized
                  && userWidget.Height == anonWidget.Height
                  && userWidget.OrderNo == anonWidget.OrderNo).Count() == 1));
            });
          });
        });
      }
    });
  }

I will not go through the boring detail of how the code works since the above code is commented. However, the last Assert part is complicated and requires further explanation:

  • For each page found from the template user
    • Ensure the new user gets the exact same page
    • Get the widgets from the template user’s page.
    • Get the widgets from the new user’s page
    • Compare each widget. For each widget
      • Ensure there’s one and only widget which has the same title, state, position etc. Not more nor less.

Whenever I make some changes in the business layer, I run the integration tests to ensure the key features are working as expected and I haven’t broken anything anywhere in the whole business layer. I just run the xunit.console.exe to run the tests on the integration test project and it generates a nice html report for me, that give me peace:

 

I generate this report by running the following command line:

d:\xunit\xunit.console.exe d:\trunk\src\Dropthings.Business.Facade.Tests\bin\Debug\Dropthings.Business.Facade.Tests.dll /html FacadeTest.html

You can use the xUnit GUI as well:

 

Test Driven Development using BDD for Unit Test

So far we had code first and then wrote the test. What about test driven development? You know, it tells you to write test first and then write code. Say you are thinking about adding a behavior:

Given PageRepository
when Insert is called
then it should insert the page in database
and clear any cached collection of pages for the user who gets the new page
and it returns the newly inserted page

Let’s write the test first.

[Specification]
public void InsertPage_should_insert_a_page_in_database_and_cache_it()
{
  var cache = new Mock<ICache>();
  var database = new Mock<IDropthingsDataContext>();
  IPageRepository pageRepository = new PageRepository(database.Object, cache.Object);
  const int pageId = 1;

  var page = default(Page);
  var samplePage = new Page() { ID = pageId, Title = "Test Page", ColumnCount = 3, 
    LayoutType = 3, UserId = Guid.NewGuid(), VersionNo = 1, 
    PageType = Enumerations.PageTypeEnum.PersonalPage, CreatedDate = DateTime.Now };

  database
      .Expect<Page>(d => d.Insert<Page>(DropthingsDataContext.SubsystemEnum.Page,
          It.IsAny<Action<Page>>()))
      .Returns(samplePage);

  "Given PageRepository".Context(() =>
  {
    // It will clear items from cache
    cache.Expect(c => c.Remove(CacheSetup.CacheKeys.PagesOfUser(samplePage.UserId)));
  });

  "when Insert is called".Do(() =>
      page = pageRepository.Insert((newPage) =>
      {
        newPage.Title = samplePage.Title;
        newPage.ColumnCount = samplePage.ColumnCount;
        newPage.LayoutType = samplePage.LayoutType;
        newPage.UserId = samplePage.UserId;
        newPage.VersionNo = samplePage.VersionNo;
        newPage.PageType = samplePage.PageType;
      }));

  ("then it should insert the page in database" +
  "and clear any cached collection of pages for the user who gets the new page" +
  "and it returns the newly inserted page").Assert(() =>
  {
    database.VerifyAll();
    cache.VerifyAll();
    Assert.Equal<int>(pageId, page.ID);
  });      
}

First we will write some dummy code in PageRepository Insert method to do nothing but return a new Page. It should fail because it won’t meet the expectation set on database object. If it does not, our test is wrong.

public Page Insert(Action<Page> populate)
        {
                    return new Page();
        } 

Running the test results in a failure as expected:

TestCase 'Given PageRepository when InsertPage is called, then it should insert the 
page in databaseand clear any cached collection of pages for the user who gets the 
new pageand it returns the newly inserted page'
failed: Moq.MockVerificationException : The following expectations were not met:
IDropthingsDataContext d => d.Insert(Page, null)
    at Moq.Mock`1.VerifyAll()
    PageRepositoryTest.cs(278,0): at 
Dropthings.DataAccess.UnitTest.PageRepositoryTest.<>c__DisplayClass35.
<InsertPage_should_insert_a_page_in_database_and_cache_it>b__34()

It tells me that there was no call to database.Insert. Good. So, it failed. We achieved the first pillar of TDD, which is to write a test and make it fail first since the expectations are not properly made by the component under test.

Let’s put the real code:

 public Page Insert(Action<Page> populate)
        {
            var newPage = _database.Insert<Page>(
                DropthingsDataContext.SubsystemEnum.Page, populate);
            RemoveUserPagesCollection(newPage.UserId);
            return newPage.Detach();
        }

Now when I run the unit tests on PageRepository, it passes the new test, along with previous tests I already have:

 

Cool! We have achieved Test Driven Development using Behavior Driven Development.

Test Driven Development using BDD for Integration Test

We just did Unit Test. What if we want to do TDD for Integration Test? How do we first write test and then write the business layer code which is integrated with other components? How do we do TDD for web layer?

The approach is same – first you write test code that gives the right input and expects the right output from the business operation. But integration tests should not only just call one business operation in isolation to ensure that it works without throwing any exception but also ensure the right behavior has been seen by performing other operations which can further support the assumption. For example, when I am testing FirstVisitHomePage, my expectation is after the first visit, user has got the right pages created. The test code verifies this by checking the returned object model. But the real world scenario is, after user visits for the first time and gets some widgets, if user comes again, user should see the same widgets. That would prove the first visit operation was successful. But I haven’t done a repeated visit to confirm the first and subsequent visit returns the same data. I should also test the following:

[Specification]
public void Revisit_should_load_the_pages_and_widgets_exactly_the_same()
{
  MembershipHelper.UsingNewAnonUser((profile) =>
  {
    using (var facade = new Facade(new AppContext(string.Empty, profile.UserName)))
    {
      UserSetup userVisitModel = null;
      UserSetup userRevisitModel = null;

      "Given an anonymous user who visited first".Context(() =>
      {
        userVisitModel = facade.FirstVisitHomePage(profile.UserName, ...);
      });

      "when the same user visits again".Do(() =>
      {
        userRevisitModel = facade.RepeatVisitHomePage(profile.UserName, ...);
      });

      "it should load the exact same pages, column and
         widgets as the first visit produced".Assert(() =>
      {
        userVisitModel.UserPages.Each(firstVisitPage =>
        {
          Assert.True(userRevisitModel.UserPages.Exists(page =>
                    page.ID == firstVisitPage.ID));
          var revisitPage = userRevisitModel.UserPages.First(page =>
                     page.ID == firstVisitPage.ID);
          var revisitPageColumns = facade.GetColumnsInPage(revisitPage.ID);
          facade.GetColumnsInPage(firstVisitPage.ID).Each(firstVisitColumn =>
          {
            var revisitColumn = revisitPageColumns.First(column =>
                 column.ID == firstVisitColumn.ID);
            var firstVisitWidgets = facade
               .GetWidgetInstancesInZoneWithWidget(firstVisitColumn.WidgetZoneId);
            var revisitWidgets = facade
               .GetWidgetInstancesInZoneWithWidget(revisitColumn.WidgetZoneId);
            firstVisitWidgets.Each(firstVisitWidget =>
                Assert.True(revisitWidgets.Where(revisitWidget =>
                    revisitWidget.Id == firstVisitWidget.Id).Count() == 1));
          });
        });
      });
    }
  });
}

This is the right way to do Integration Tests. When you are performing integration test, you have to think the opposite of writing unit test. In unit test, your approach is to test one and only one class in complete isolation calling one method and stubbing/mocking everything else out. But in integration test, you should test not only just one operation, but to support the test expectations, you should perform other related operations to ensure that the operation under test really does what it’s expected to do. I have generalized the possible test cases into these categories:

  • When you test an operation that creates new data (eg insert rows in database or call a webservice to create some entity), ensure the operation was carried out properly by:
    • Calling other operations that would read that data (read the row again or call some other webservice to get the created entity). It would fail if the data *was not* inserted properly (eg insert child rows). This is positive test.
    • Calling other operations that would fail if the insert was successful. Eg inserting the same row again will produce constraint violation. This is negative test.
  • When you test an operation that updates some data (eg update rows in database), ensure the operation updated the data properly by
    • Calling other operations that will use the updated data and they would fail if the data was not updated properly (eg make two consecutive money transfer where insufficient balance in account after the first money transfer). This is positive test.
    • Calling other operations that would fail if the update was successful. Eg try to insert a new row in database using the same values after update should produce constraint violations. This is negative test.
  • When you test an operation that deletes some data, ensure the operation deleted the data properly by
    • Calling other operations that would fail if the data existed (eg insert same row again to produce constraint violation).
    • Calling operations that would fail if the data was deleted properly. Eg try inserting child rows for the non-existed row.

You must do positive and negative tests in integration tests, even if you are doing it in unit tests. Otherwise you won’t have the confidence that your tests are covering major behaviors of the system. One of the benefit of integration tests is it tests the unpredictability of the infrastructure more than testing your own code (assuming your own code is well unit tested already). So, it is important you cover as much positive and negative scenarios as possible to rule out infrastructure variables.

Conclusion

Hope this gave you example of some realistic unit and integration testing using an approach that I find useful. There are many ways you can do TDD. You don’t need to follow a certain approach all the time. But I found that using BDD to do TDD was the most effective and it reduced the number of unit test methods I had to write in order to test the complete behaviors of the components. Doing BDD using xUnit and Subspec makes test code more readable and natural to write. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Omar Al Zabir


Member
I am: Chief Architect, SaaS Platform, BT Innovate & Design (British Telecom). Visual C# MVP '05-'07, ASP.NET MVP '08
I was: Co-founder & CTO, Pageflakes(www.pageflakes.com)

My Blog: http://msmvps.com/blogs/omar/
My Specialization: Web 2.0 Rich AJAX Applications, Level 3 SaaS, Performance and Scalability of Web Apps.
My Book: Building a Web 2.0 portal using ASP.NET 3.5. Also on Amazon
My Email: OmarALZabir at gmail dot com
My Interest: Travel, Performance and Scalability Challenges.
My Projects:
Open Source Web 2.0 AJAX Portal
Smart UML - Freehand UML Designer
RSS Aggregator both Outlook and Standalone
Store Front in JSP but ASP.NET style

My Articles:
99.99% Available Production Architecture
Build GoogleIG like Ajax Start Page in 7 days
10 ASP.NET Performance and Scalability Secrets
ASP.NET AJAX under the hood secrets
UFrame: goodness of UpdatePanel and IFRAME combined
Fast ASP.NET web page loading
Fast, Scalable, Streaming AJAX Proxy
Using COM safely inside "using" block without requiring interop assembly
Implementing Word Like Automation Model
Distributed Command Pattern
StickOut - .NET 2.0, VSTS, Outlook Addin,
Occupation: Architect
Company: British Telecom
Location: Bangladesh Bangladesh

Other popular Testing and QA articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 6 of 6 (Total in Forum: 6) (Refresh)FirstPrevNext
GeneralYou got my vote for "Best ASP.NET article of November 2009" PinmemberMarcelo Ricardo de Oliveira0:21 12 Dec '09  
GeneralNice reading PinmemberPetr Pechovic3:46 26 Nov '09  
GeneralNice post PinmemberS. M. SOHAN8:08 24 Nov '09  
GeneralAnother excellent post PingroupMd. Marufuzzaman9:06 21 Nov '09  
GeneralPretty useful and bang on time. PinmemberRajesh Pillai6:16 21 Nov '09  
GeneralNice article PinmentorNick Butler2:42 21 Nov '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.

PermaLink | Privacy | Terms of Use
Last Updated: 24 Nov 2009
Editor:
Copyright 2009 by Omar Al Zabir
Everything else Copyright © CodeProject, 1999-2010
Web21 | Advertise on the Code Project