If all of your unit tests were actually integration tests, it could potentially be lengthy to call and test, and even more challenging to configure. What if you are developing offline and that web service is not available? Should you then not be able to test your code? The answer of course is 'no' you should still be able to test your code.
Use of a mocking framework like Moq allows us to stub out these dependencies with expected behavior, thus allowing the code to be tested independent of the actual integration with that dependency. The primary example of this would be to stub out data access calls that would normally at runtime actually call the database.
The following example relies on the Repository pattern and an Interface provided with the calls that would be implemented to reach out to the database. This abstraction allows Moq to substitute the implementation and behavior to a predetermined expectation for our unit test. If you happen to already be using the Repository pattern but not unit testing, you should be able to fit the code below after understanding it into your solution to being building up some unit tests.
Here is the Repository Interface we are working with for the example:
public interface IRepository<T> where T : class { IList<T> GetAll(); }
Here is the implemented Repository class. There is a lot more abstraction we could do to the Repository in addition to using the UnitOfWork pattern, but the focus here is on the unit test so this is a basic implementation:
public class PersonRepository : IRepository<Person> { private AdventureWorksEntities db = new AdventureWorksEntities(); public IList<Person> GetAll() { var people = from p in db.People select p; return people.ToList(); } }
In this test project I used Entity Framework and connected it to the 'AdventureWorks' database. I expanded on the Person POCO and added an arbitrary method that would find an employee by 1st and last name. In reality a method like this would probably be on a generic repository that takes an expression as the parameter, but again the focus here is to show how we can unit test this method that uses the Repository without actually calling the database. Here is the Partial Class I added with the 'GetPersonByName' method:
public partial class Person { private readonly IRepository<Person> personRepository; public Person(IRepository<Person> personRepository) { this.personRepository = personRepository; } public Person GetPersonByName(string firstName, string LastName) { var allPeople = this.personRepository.GetAll(); return allPeople.Where(x => x.FirstName.ToLower() == firstName.ToLower() && x.LastName.ToLower() == LastName.ToLower()) .FirstOrDefault(); } }
The last coding step is to write the unit test. I 1st need to build up a Person collection that will be used by the framework. This can be done in a Setup method with the [TestInitialize] attribute assigned. I will create a simple test that will ensure a valid instance of Person is returned. The idea here is to test the code within the method to make sure that logic is sound and working as opposed to the actual database call itself. I will leverage Moq to inject the Mock Interface into the Person class. If you have not used Dependency Injection, here is another 'plus' for doing it and it's benefits for testing. Here is the complete PersonTest class with the simple unit test:
[TestClass] public class PersonTest { private IList<Person> people; [TestInitialize] public void Setup() { people = new List<Person>() { new Person() { Title = "Mr.", FirstName = "Allen", LastName = "Conway", PersonType = "EM" }, new Person() { Title = "Mr.", FirstName = "John", LastName = "Smith", PersonType = "SC" } }; } [TestMethod] public void PersonSearch_ShouldFind_ValidInstance() { //Arrange var repositoryMock = new Mock<IRepository<Person>>(); //Setup mock that will return People list when called: repositoryMock.Setup(x => x.GetAll()).Returns(people); var person = new Person(repositoryMock.Object); //Act (mocked up IRepository will supply the data when calls are made to the repository) var singlePerson = person.GetPersonByName("Allen", "Conway"); //Assert Assert.IsNotNull(singlePerson); // Test if null Assert.IsInstanceOfType(singlePerson, typeof(Person)); // Test type } }
If you run the unit test above you will see it passes and passes quite quickly (in about 100ms on my machine). Now if I had to actually call out to the database it would have returned the 20,000 rows in the Person table and that is not what I'm testing here. To prove the mock object (in this instance it's actually a stub returning a known state but that's for another post) behaved and returned the collection we expected, right click on the test name and select to debug (I'm using the MSTest runner in VS.NET 2013). If you walk through the code, guess what is returned when the call to .GetAll() on the repository is made within the 'GetPersonByName' method? Our collection created within the test class:
This is only the basics of unit testing and using a mocking framework like Moq, but I put it out there because I see such a disparity between creating unit tests and not creating / using them in our field. It seems like people are 'all in Gung-Ho' or do absolutely none of it. Hopefully this post showed a straight forward and simple example for those wanting to get into unit testing or begin using a mocking framework that are not already doing so today.
Great post Allen. I was thinking of following your steps since unit testing using moq is still new to me.
ReplyDeleteHowever, the Find() method on my project (similar to your GetPersonByName() method) along with GetAll() method are in the repository and my POCOs have no methods whatsoever, be it constructors or business logic methods.
How would I instantiate a person object without passing a .Object parameter for testing and also how would I call Find() from the repository?
Thanks