Posts tagged ‘Rhino Mocks’

Finally! I’ve been itching to get into the latest incarnation of the EF for a while now and finally I had the opportunity to take it around the block (kick the tires and generally rough it up). My main interest in EF 2.0 was the supposed support for Unit Testing and the improvements on using POCO to map to the Data Model.

I have to admit, although I liked EF 1.0 when I first started using it, one of my biggest bug bears was the fact that you had to “disconnect” your entities before you could really work with them outside the context (no pun intended) of the Entity Framework. I was also quite miffed when I discovered there was no easy way to mock the underlying data layer so I ended up with code like this:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out Customer o_customer)
    {
        if (string.IsNullOrEmpty(i_customerId))
        {
            throw new ArgumentException("Parameter cannot be null.", "i_customerId");
        }
        int numericVal;
        if (!int.TryParse(i_customerId, out numericVal))
        {
            throw new ArgumentException("Parameter cannot be non-numeric.", "i_customerId");
        }
        if (numericVal < 0 || numericVal > 9999)
        {
            throw new ArgumentOutOfRangeException("i_customerId");
        }

        m_customerRepository.Load(i_customerId, out o_customer);

        if (o_customer != null)
        {
            if (!string.IsNullOrEmpty(o_customer.ContactName) && o_customer.ContactName.Contains(" "))
            {
                o_customer.ContactName = o_customer.ContactName.Trim(' ');
                string[] names = o_customer.ContactName.Split(' ');
                if (names.Length > 1)
                {
                    names[names.Length - 1] = names[names.Length - 1].ToUpper();
                }
                o_customer.ContactName = string.Join(" ", names);
            }
        }
    }

In this case, m_customerRepository is the injected ICustomerRepository instance. When we look at the implementation of the actual data layer class (which does not get tested by the Unit Test, we find that inside the Load method we have the following:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out BaseCustomer o_customer)
    {
        Customer customer = (CustomerSet.Where(cust => !string.IsNullOrEmpty(cust.CustomerID) &&
                                                       cust.CustomerID == i_customerId)).First();
        if (customer != null)
        {
            o_customer = new BaseCustomer()
                             {
                                 Address = customer.Address,
                                 City = customer.City,
                                 CompanyName = customer.CompanyName,
                                 ContactName = customer.ContactName,
                                 ContactTitle = customer.ContactTitle,
                                 Country = customer.Country,
                                 CustomerID = customer.CustomerID,
                                 Fax = customer.Fax,
                                 Phone = customer.Phone,
                                 PostalCode = customer.PostalCode,
                                 Region = customer.Region
                             };
        }
        else
        {
            o_customer = null;
        }
    }

Not the best way of doing things, that is for sure! In fact it is downright ugly (IMHO). So when I heard that there were improvements to the EF for .NET 4.0, especially in the area of Unit Testing I was curious to say the least. As I delved in deeper I started finding more and more things that made it more attractive to my style of development. For example one of the beauties of EF 2.0 is the fact that you can remove the CustomTool that generates the entity classes that are bound to the data model (through the edmx file). When you do this, you effectively get rid of the code generation for the EF instance that you have loaded in your project. There are some excellent examples (and walkthroughs available) from the ADO.NET Team blog:

POCO in Entity Framework : Part 1 – The Experience (excellent walkthrough on removing the CustomTool)

POCO in Entity Framework : Part 2 – Complex Types, Deferred Loading and Explicit Loading

POCO in Entity Framework : Part 3 – Change Tracking with POCO

So now what? Great! So now I can use my POCO to update the Data Model. But I still hadn’t found out how to do true unit testing with DI and mocking? I was quite flummoxed until I realized (with a helpful pointer from a friend at Microsoft – thanks Jason) that the answer was staring me in the face:

“Can’t you create a mock class that derives from IObjectSet instance yourself, or is there a problem doing that?”

Well yes, I did have a problem with that – it meant that I would have to write more code. I was naively hoping to have something like:


List<Customer> cusList = TestHelper.CreateCustomerList();
IObjectSet<Customer> context = cusList.AsObjectSet();

So I was being lazy… I guess that, with each version of .NET, I had become more and more accustomed to so much being done for me that stumbling across something as “simple” as creating an AsObjectSet() function that was not available was bit of a shock. More so when you look at what IS available on a List<entity> method / property list.

At first I contented myself with just doing what was obvious – create a mock class that inherited from IObjectSet<Customer>, before I realized (with another push from Jason) that I could make it more generic and have a MockObjectSet<T> class:


    internal class MockObjectSet<T> : IObjectSet<T>
        where T : class
    {
        public MockObjectSet(List<T> entityList)
        {
            if (entityList == null)
            {
                throw new ArgumentNullException("entityList");
            }
            else
            {
                _repository = entityList.ToList();
            }
        }

        IList<T> _repository;

        #region IObjectSet<T> Members

        public void AddObject(T entity)
        {
            _repository.Add(entity);
        }

        public void Attach(T entity)
        {
            this.AddObject(entity);
        }

        public void DeleteObject(T entity)
        {
            _repository.Remove(entity);
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return _repository.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _repository.GetEnumerator();
        }

        #endregion

        #region IQueryable Members

        public Type ElementType
        {
            get { return typeof(T); }
        }

        public System.Linq.Expressions.Expression Expression
        {
            get { return _repository.AsQueryable<T>().Expression; }
        }

        public IQueryProvider Provider
        {
            get { return _repository.AsQueryable<T>().Provider; }
        }

        #endregion
    }

It is important to note here that the TestHelper.CreateCustomerList() function has several overrides and returns a List<Customer> filled with dummy data.

After playing around a bit I realized that I could actually just create an Extension Method that would create an instance of the mock CustomerSet and therefore I could call it from within my Unit Test code. The Extension Method looks like this:


    public static class ObjectSetExtension
    {
        public static IObjectSet<T> AsObjectSet<T>(this List<T> entities) where T : class
        {
            return new MockObjectSet<T>(entities);
        }
    }

Now if we revisit the unit test code, we get the following:


        [TestMethod]
        public void TestLoadValidCustomerContactNameWithSurname()
        {
            // Arrange
            // Create the stub instance
            INorthwindContext context = MockRepository.GenerateStub<INorthwindContext>();
            // Create the dummy data
            const string customerId = "555";
            const string contactName = "James Person";
            IObjectSet<Customer> customers = TestHelper.CreateCustomerList(contactName, customerId).AsObjectSet();

            // declare the dummy instance we are going to use
            Customer loadedCustomer;

            // Explicitly state how the stubs should behave
            context.Stub(stub => stub.Customers).Return(customers);

            // Create a real instance of the CustomerManager that we want to put under test
            Managers.CustomerManager manager = new Managers.CustomerManager(context);

            // Act
            manager.Load(customerId, out loadedCustomer);

            // Assert
            context.AssertWasCalled(stub => { var temp = stub.Customers; });
            // Check the expected nature of the dummy intance
            Assert.IsNotNull(loadedCustomer);
            Assert.IsNotNull(loadedCustomer.ContactName);
            Assert.IsTrue(loadedCustomer.ContactName == "James PERSON");
        }

If we compare the two managers again (the manager that I had created in a previous blog posting depended on EF 1.0), we will see that the EF 2.0 instance actually contains lambda expressions to do the queries.

EF 1.0:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out Customer o_customer)
    {
        if (string.IsNullOrEmpty(i_customerId))
        {
            throw new ArgumentException("Parameter cannot be null.", "i_customerId");
        }
        int numericVal;
        if (!int.TryParse(i_customerId, out numericVal))
        {
            throw new ArgumentException("Parameter cannot be non-numeric.", "i_customerId");
        }
        if (numericVal < 0 || numericVal > 9999)
        {
            throw new ArgumentOutOfRangeException("i_customerId");
        }

        m_customerRepository.Load(i_customerId, out o_customer);

        if (o_customer != null)
        {
            if (!string.IsNullOrEmpty(o_customer.ContactName) && o_customer.ContactName.Contains(" "))
            {
                o_customer.ContactName = o_customer.ContactName.Trim(' ');
                string[] names = o_customer.ContactName.Split(' ');
                if (names.Length > 1)
                {
                    names[names.Length - 1] = names[names.Length - 1].ToUpper();
                }
                o_customer.ContactName = string.Join(" ", names);
            }
        }
    }

EF 2.0:


    /// <summary>
    /// Loads a customer instance with the relevant information from the database.
    /// </summary>
    /// <param name="i_customerId">The customerId of the customer data to be retrieved.</param>
    /// <param name="o_customer">The customer instance to be created.</param>
    public void Load(string i_customerId, out Customer o_customer)
    {
        if (string.IsNullOrEmpty(i_customerId))
        {
            throw new ArgumentException("Parameter cannot be null.", "i_customerId");
        }
        int numericVal;
        if (!int.TryParse(i_customerId, out numericVal))
        {
            throw new ArgumentException("Parameter cannot be non-numeric.", "i_customerId");
        }
        if (numericVal < 0 || numericVal > 9999)
        {
            throw new ArgumentOutOfRangeException("i_customerId");
        }

        var customers = (from cus in _context.Customers
                         where cus.CustomerID == i_customerId
                         select cus);
        if (customers.Count() == 1)
        {
            o_customer = customers.Single<Customer>();
        }
        else
        {
            o_customer = null;
        }

        if (o_customer != null)
        {
            if (!string.IsNullOrEmpty(o_customer.ContactName) && o_customer.ContactName.Contains(" "))
            {
                o_customer.ContactName = o_customer.ContactName.Trim(' ');
                string[] names = o_customer.ContactName.Split(' ');
                if (names.Length > 1)
                {
                    names[names.Length - 1] = names[names.Length - 1].ToUpper();
                }
                o_customer.ContactName = string.Join(" ", names);
            }
        }
    }

In the second code, snippet, because I am calling straight to an instance of IObjectSet<Customer>, it could either be my mocked one or the actual Entity Framework instance, which looks like this (thanks to POCO binding):


    public class NorthwindContext : ObjectContext, INorthwindContext
    {

        public NorthwindContext()
            : base("name=NorthwindEntities", "NorthwindEntities")
        {
        }

        private ObjectSet<Order> _orders;
        private ObjectSet<Employee> _employees;
        private ObjectSet<Customer> _customers;

        #region INorthwindContext Members

        IObjectSet<Employee> INorthwindContext.Employees
        {
            get { return _employees ?? (_employees = CreateObjectSet<Employee>()); }
        }

        IObjectSet<Customer> INorthwindContext.Customers
        {
            get { return _customers ?? (_customers = CreateObjectSet<Customer>()); }
        }

        IObjectSet<Order> INorthwindContext.Orders
        {
            get { return _orders ?? (_orders = CreateObjectSet<Order>()); }
        }

        #endregion
    }

This means that when I run my code coverage for the EF 2.0 version, I will be hitting the true boundary between the entity and the model, thanks to a combination of POCO and the separation of concerns brought about by IObjectSet.

Ok, so there’s no kitchen sink – what would you do with it if there was?

  • Share/Bookmark

Recently a colleague pointed out that my unit test were not following the AAA (Arrange, Act and Assert) structure that they had become accustomed to seeing and as they had understood Unit Tests should be. Although I had argued the point that there were many ways to setup and execute the test I can understand where the confusion can come in when mocking with Rhino Mocks.

I’m an advocate of using what comes natural to you as long as the outcomes are consistent; however I accept that there needs to be some uniformity when working in a team for the simple case of a collective understanding – as long as it is not at the behest of an individual’s ego.

The primary issue boiled down to the difference between the way that the test was prepared in my original blog posting:


[TestMethod]
public void TestInsertValidCustomerContactNameWithSurname()
{
    // Create the mock instance
    ICustomerRepository customerRepository = m_mockRepository.DynamicMock<ICustomerRepository>();

    Customer newEntry = TestHelper.CreateCustomer("James Person");

    // Now we set our expectations - when a null is passed the underlying method should throw an exception
    Expect.Call(() => customerRepository.Insert(newEntry)).Constraints(Property.Value("ContactName", "James PERSON"));

    // Replay our expectations
    m_mockRepository.ReplayAll();

    // Create a real instance of the CustomerManager that we want to put under test
    Managers.CustomerManager manager = new Managers.CustomerManager(customerRepository);

    manager.Insert(newEntry);
}

And setting it up in a true AAA sense:


[TestMethod]
public void TestInsertValidCustomerContactNameWithSurname()
{
    // Arrange
    // Create the stub instance
    ICustomerRepository customerRepository = MockRepository.GenerateStub<ICustomerRepository>();

    // Create the dummy instance to be used as a parameter
    Customer newEntry = TestHelper.CreateCustomer("James Person");

    // Create a real instance of the CustomerManager that we want to put under test
    Managers.CustomerManager manager = new Managers.CustomerManager(customerRepository);

    // Act
    manager.Insert(newEntry);

    // Assert - here we also check the property value ContactName to make sure that it is as expected.
    customerRepository.AssertWasCalled(stub => stub.Insert(newEntry), stub => stub.Constraints(Property.Value("ContactName", "James PERSON")));
}

Notice how the second example shows very distinct Arrange, Act and Assert structure.

Both methodologies result in the same outcome and at the end of the day I would say that you should use what works for you – as long as other people can understand the logic (“What if you should get hit by a bus?”).

  • Share/Bookmark

In continuation with the Dependency Injection entry of my previous blog, now we look at how we can leverage the work we did to use it with a mocking framework to perform proper unit testing.

There are numerous blogs and articles about different Mocking frameworks and after taking a couple of them around the block and kicking the tires I settled on RhinoMocks as the best fit for my needs. I put together a little table to try and capture my thought process on choosing the appropriate framework and although this is not an extensive list it met my needs at the time:

  Ease of use Cost Likes Dislikes Conclusion
RhinoMocks Relatively easy because it’s strongly-typed, which makes the syntax great and"safe". Free Strongly typed instancing – no need to use string references. None so far "Allows for generating a mock object of a class without the interface a requirement. What is powerful about this technique, is that you can request Rhino.Mock to create a mock object of a class (even something like System.Net.WebClient) and then pass that mock object into the implementation of your class.

Now any calls to System.Net.WebClient will be to your mock object even though the target library was compiled to use System.Net.WebClient.

Furthermore, the setting up of method call expectations is compiled, rather than just string names for the methods."
NMock Use of strings to call property methods / normal methods. Free Pales to insignificance in contrast to RhinoMocks or TypeMock Need to use string declarations for instancing. "Requires the object to be mocked so support an interface. Mock objects are generated at runtime to implement the interface. Programmatically you inject method implementations on the mock object so that it expects certain calls and returns values for those calls. This works great until the class you want to mock does not implement an interface."
TypeMock Extremely easy to implement mocking because it uses the .NET framework profiler API to monitor an application’s execution. When a method is called, the CLR notifies Isolator. The framework can then return mocked values and override the original code completely. Expensive The fact that it "plugs-in" to the CLR and captures type references, means that no code changes need to be done on legacy components. Prohibitively Expensive. "Allows for the runtime generation of type objects on the fly within the target project, not just within the test. As a result, you can identify the types you wish TypeMock engine to intercept and then, whenever the target library instantiates those objects, a mock object will be created instead."


If it were not for the pricing this would be the choice (10 out of 10):

Complete Bundle License Per User (12 months): $749.00

Complete Bundle Build Server License (5 VM): $1,999.00

ASP.NET Bundle License Per User (12 months): $599.00

ASP .NET Bundle Build Server License (5 VM): $1,449.00

So what is mocking?

Well, for those readers that are not familiar with mocking it can be summed up with a reference to Martin Fowler in his Mock’s aren’t Stubs post

Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Whilst doing my research into the use of Mocking Frameworks and what I wanted to get out of them I came across a few references to “Isolation Frameworks” that seemed to be used on top of the reference to Mocking Frameworks and the idea is effectively that you use the mocking framework of your choice to isolate the unit under test by specifying the expected behavior of the mocked object. We are still mocking, but with in the context of testing an acute code path of a particular class.

How does it fit in with the example?

In my previous blog, I introduced the very basic example of dependency injection to illustrate the idea behind isolating the dependencies in order to easily “injection” an alternative. Now that we have the ability to inject an alternative, we’ll create mock instances of those dependencies and use those instead of the real ones.

As a reminder, here is the definition of the IEmployeeConnector interface that we created when setting up the Dependency Injection in the EmployeeConnector class:

  1. public interface IEmployeeRepository
  2. {
  3.     /// <summary>
  4.     /// A string containing the connection details for the underlying data repository resource.
  5.     /// </summary>
  6.     string ConnectionString { get; set; }
  7.  
  8.     /// <summary>
  9.     /// Inserts a new Employee instance in to the data repository.
  10.     /// </summary>
  11.     /// <param name="i_employee">The Employee instance to insert.</param>
  12.     void Insert(Employee i_employee);
  13.  
  14.     /// <summary>
  15.     /// Loads (retrieves) an Employee instance from the data repository.
  16.     /// </summary>
  17.     /// <param name="i_employeeId">The unique identifier fro the Employee instance.</param>
  18.     /// <param name="o_employee">The Employee instance retrieved.</param>
  19.     void Load(int i_employeeId, out Employee o_employee);
  20.  
  21.     /// <summary>
  22.     /// Updates an existing Employee instance in the data repository.
  23.     /// </summary>
  24.     /// <param name="i_employee">The Employee instance to update.</param>
  25.     void Update(Employee i_employee);
  26.  
  27.     /// <summary>
  28.     /// Updates an existing Employee instance from the data repository.
  29.     /// </summary>
  30.     /// <param name="i_employee">The Employee instance to delete.</param>
  31.     void Delete(Employee i_employee);
  32.  
  33.     /// <summary>
  34.     /// Retrieves all employee instances  from the data repository.
  35.     /// </summary>
  36.     /// <returns>List of EMployee instances retrieved from the data repository.</returns>
  37.     List<Employee> LoadAllEmployees();
  38. }

With this in mind, we can then test the functionality of the LoadAllEmployees function:

  1. /// <summary>
  2. /// Retruns a sorted list of all employees. Sorted by Last Name.
  3. /// </summary>
  4. /// <returns>List of sorted employees.</returns>
  5. public List<Employee> LoadAllEmployees()
  6. {
  7.     List<Employee> retVal = m_employeeRepository.LoadAllEmployees();
  8.     if (retVal.Count > 0)
  9.     {
  10.         retVal.Sort(delegate(Employee e1, Employee e2)
  11.         {
  12.             return e1.LastName.CompareTo(e2.LastName);
  13.         });
  14.     }
  15.     return retVal;
  16. }

This then implies that we need to create a mock instance of the IEmployeeConnector that will be passed into the constructor of the EmployeeConnector class. The following MSTest method provides an example of how we can do this:

  1. [TestMethod]
  2. public void TestGetSortedEmployeeList()
  3. {
  4.     // Create the mock instance
  5.     IEmployeeRepository eConnect = m_mockRepository.DynamicMock<IEmployeeRepository>();
  6.  
  7.     // Here we create an actual instance
  8.     List<Employee> filledCollection;
  9.     FillCollection(ObjectInstances.FilledInstance, out filledCollection);
  10.  
  11.     // Now we set our expectations
  12.     Expect.Call(eConnect.LoadAllEmployees()).Return(filledCollection);
  13.  
  14.     // Replay our expectations
  15.     m_mockRepository.ReplayAll();
  16.  
  17.     // Create a real instance of the EmloyeeConnector that we want to put under test
  18.     EmployeeManager manager = new EmployeeManager(eConnect);
  19.  
  20.     List<Employee> employees = manager.LoadAllEmployees();
  21.  
  22.     Assert.IsNotNull(employees);
  23.  
  24.     Assert.IsTrue(employees.Count > 0);
  25.  
  26.     Assert.IsTrue(employees[0].LastName == "Anderson");
  27. }

This test method will test the Sort functionality of the LoadAllEmployees function on the EmployeeConnector instance in isolation, because we have told the mocking framework exactly how we want it to behave with the Expect.Call() function.

When the method does get called within the LoadAllEmployees of the EmployerConnector method the RhinoMocks framework will pass back the filledCollection instance that we had constructed:

  1. Expect.Call(eConnect.LoadAllEmployees()).Return(filledCollection);

As a brief note, the Test utility method FillCollection() will fill the passed in List collection with dummy data that the Test method can then check against in the Assert statements:

  1. private static void FillCollection(ObjectInstances instanceType, out List<Employee> filledCollection)
  2. {
  3.     filledCollection = new List<Employee>();
  4.     if (instanceType == ObjectInstances.FilledInstance)
  5.     {
  6.         Employee instance = new Employee();
  7.         instance.Address = "123 Road";
  8.         instance.BirthDate = new DateTime(1975, 3, 15);
  9.         instance.City = "Acity";
  10.         instance.Country = "Acountry";
  11.         instance.EmployeeID = 1234;
  12.         instance.Extension = "5678";
  13.         instance.FirstName = "John";
  14.         instance.HireDate = new DateTime(2005, 5, 21);
  15.         instance.HomePhone = string.Empty;
  16.         instance.LastName = "Doe";
  17.         instance.Notes = string.Empty;
  18.         instance.Photo = string.Empty;
  19.         instance.PostalCode = "01234";
  20.         instance.Region = "Aregion";
  21.         instance.ReportsTo = 1;
  22.         instance.Title = "General Whatsit";
  23.         instance.TitleOfCourtesy = "Mr.";
  24.         filledCollection.Add(instance);
  25.  
  26.         instance = new Employee();
  27.         instance.Address = "123 Street";
  28.         instance.BirthDate = new DateTime(1965, 6, 24);
  29.         instance.City = "Acity";
  30.         instance.Country = "Acountry";
  31.         instance.EmployeeID = 5678;
  32.         instance.Extension = "2003";
  33.         instance.FirstName = "Samantha";
  34.         instance.HireDate = new DateTime(2007, 6, 24);
  35.         instance.HomePhone = string.Empty;
  36.         instance.LastName = "Anderson";
  37.         instance.Notes = string.Empty;
  38.         instance.Photo = string.Empty;
  39.         instance.PostalCode = "01234";
  40.         instance.Region = "Aregion";
  41.         instance.ReportsTo = 1;
  42.         instance.Title = "General Whatchamacallit";
  43.         instance.TitleOfCourtesy = "Ms.";
  44.         filledCollection.Add(instance);
  45.  
  46.         instance = new Employee();
  47.         instance.Address = "405 Avenue";
  48.         instance.BirthDate = new DateTime(1980, 2, 10);
  49.         instance.City = "Acity";
  50.         instance.Country = "Acountry";
  51.         instance.EmployeeID = 9876;
  52.         instance.Extension = "0987";
  53.         instance.FirstName = "Donna";
  54.         instance.HireDate = new DateTime(2000, 4, 18);
  55.         instance.HomePhone = string.Empty;
  56.         instance.LastName = "Kebab";
  57.         instance.Notes = string.Empty;
  58.         instance.Photo = string.Empty;
  59.         instance.PostalCode = "01234";
  60.         instance.Region = "Aregion";
  61.         instance.ReportsTo = 1;
  62.         instance.Title = "Manager";
  63.         instance.TitleOfCourtesy = "Mrs.";
  64.         filledCollection.Add(instance);
  65.     }
  66. }

Visual Studio Test Edition

One of the wonders of the Visual Studio Test Edition is the fact that you can run the MSTests and also specify the Assembly that you want to perform code-coverage:

Visual Studio Code Coverage Dialog

Once this is done, then when you run the MSTest you can view the code paths that were covered by the test (with highlighting):

Code Coverage Results - Covered

And also those code paths that were not covered (with highlighting):

Code Coverage Results - Not covered

  • Share/Bookmark