Pages

Monday, January 6, 2014

Test Driven Development and FakeItEasy

Recently I've been working with Test Driven Development (TDD) and FakeItEasy. Test Driven Development is a test-first approach to developing software and FakeItEasy is a mocking framework. Using TDD and FakeItEasy together can help you build maintainable, loosely coupled solutions. Here are some of the key TDD principles:
  • Write a failing unit test first.
  • Write the minimum code needed to get the test to pass.
  • Refactor code to acceptable standards.
  • Use a mocking framework to test external dependencies.

Here are some of the benefits I’ve experienced recently using Test Driven Development and FakeItEasy:
  • Writing unit tests first helps drive the design of the project; it makes the solution more component based.
  • Mocking objects helps you build Interface based components that support dependency injection.
  • Test Driven Development helps you understand the requirements and the acceptance criteria for each use case/ user story.
  • Unit tests – with descriptive names – can provide valuable system documentation.

Here's an example of how to use FakeItEasy:

Step 1: Open Visual Studio. Add three class library projects to your solution:
-- DataService
-- Tests.IntegrationTests
-- Tests.UnitTests

Step 2: Right-click project “Tests.UnitTests”. Select “Manage NuGet Packages”:
-- Install-Package NUnit
-- Install-Package FakeItEasy
-- Add a new class called “When_calling_fake_data_service.cs” 

Step 3: Add two unit tests to class When_calling_fake_data_service.cs. These  tests won’t pass yet.
        [Test]
        public void Should_call_GetOrders()
        {
            // Arrange
            var fakeDbClient = A.Fake<IDbClient>(); 

            // Create system under test
            var service = new DAL(fakeDbClient); 

            // Act
            service.GetOrders(); 

            // Assert
            A.CallTo(() => fakeDbClient.GetOrders()).MustHaveHappened();
       }    

[Test]
       public void Should_get_fake_orders()
       {
     // Create a fake expected response
            var expectedData = new List<Order>
                {
                    new Order() {OrderId = 100, Description = "desc 100"},
                    new Order() {OrderId = 200, Description = "desc 200"},
                    new Order() {OrderId = 300, Description = "desc 300"}
                };

            // Arrange
            var fakeDbClient = A.Fake<IDbClient>(); 

            // Tell FakeItEasy to return fake response when GetOrders is called
            A.CallTo(() => fakeDbClient
                .GetOrders())
                .Returns(expectedData); 

            // Create system under test
            var service = new DAL(fakeDbClient);

            // Act
            var result = service.GetOrders(); 

            // Assert
            Assert.AreEqual(expectedData, result, "Incorrect result from GetOrders!");
       }

Step 4: Select project “DataService”. Add the following code to class “DAL.cs”: 
    public class Order
    {
        public int OrderId { get; set; }
        public string Description { get; set; }
    } 

    public interface IDbClient
    {
        List<Order> GetOrders();
    }

    public class DAL
    {
        private readonly IDbClient _db; 

        public DAL(IDbClient db)
        {
            _db = db;
        } 

        public List<Order> GetOrders()
        {
            return _db.GetOrders();
        }
    } 

    public class DbClient : IDbClient
    {
        public List<Order> GetOrders()
           {
            var lstOrders = new List<Order>
                {
                    new Order() {OrderId = 1, Description = "desc 1"},
                    new Order() {OrderId = 2, Description = "desc 2"},
                    new Order() {OrderId = 3, Description = "desc 3"}
                }; 

            return lstOrders;
        }
    } 

Step 5: Run both unit tests – they should pass now.  

So what? What did we learn/ achieve?
  • FakeItEasy enables developers to test modules in isolation.
  • Creating interfaces is a best practice – it’s the first step towards mocking external systems.
  • Writing unit tests first helps developers to understand requirements and build component based systems.
  • Unit tests – with descriptive names – can provide valuable system documentation. 
For more info check out:
http://pluralsight.com/ - Test First Development Part I & II
https://github.com/FakeItEasy/FakeItEasy/wiki
http://en.wikipedia.org/wiki/Test-driven_development
http://en.wikipedia.org/wiki/Unit_testing







2 comments:

  1. Greg: Please do a talk (or preferably a series) on unit testing and mocking!

    ReplyDelete