AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=1277&pId=-1
Mocking in Unit Tests
page
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 35501/ 70

Introduction

Unit testing adds a new capability to application development testing. The ability to execute code that ensures the design, logic, and functionality of an application is the key to developing successful, bug-free software. However, there are times where unit testing is not enough. This is especially true when the properties/methods you really need to test are declared private, protected, or internal/friend.

How do you compensate for that?  Inheritance can work; for instance, your unit test can inherit from the class that defines protected methods, and validate these internal methods in that manner.  That is useful, but not always efficient.  In addition, what about internal/friend and private methods/properties?

Another option is reflection.  Reflection has the capabilities to peek underneath an object, inspect its metadata, and through that get/set properties or invoke methods that you normally could not access.  This is one of the means we will look at.

Secondly, there is the concept of mocking/stubbing classes in an application.  Mocking is the art of inspecting an object's behavior to ensure that it makes all of the correct assignments or operations.  It even can be used to test how the code handles if a different value is returned or if an exception is thrown.  Martin Fowler calls this process "behavior verification," which is exactly what is done with mocks.

From this, there are several ways to do this.  The first that I will show you is to create your own way to test the logic.  I created a set of components to do this in my Nucleo Framework to test the logic.  By inserting the logic you would like to implement directly into a test, you can use these objects to mock the return value.  It is not illustrating the full value of mocking, as we shall see in the following example using the TypeMock library, a freely-available library that intercepts calls to your method and allows you to verify/control the processing that goes on in a method.  We shall see more examples below.

Reflection

The .NET Framework has the ability to reflect and gather metadata about types in an assembly.  The Type class has several methods define that return objects representing a property, method, etc.  These objects are suffixed with -Info and are defined in the System.Reflection namespace.  For instance, if you wanted to get properties of a class, you use GetProperties() to get a list of properties or GetProperty() to get a specific named property.  For each object the type class has these methods defined or you can use GetMember()/GetMembers() to get the MemberInfo objects you may be looking for.

Reflection has some capabilities to get/set values, which help in getting/setting values for an object.  You can somewhat mock a property value because you can change it to be whatever you want to test it as.  This is the capability I build into a Reflection Mock class that made it easier to perform logic mocking in unit tests, but is far short of an actual mock class.

See the Reflection overview for more information.

Logic Mocking through Reflection Mock

For those who code using Test-Driven Development, creating the unit test is the key to designing successful software and there are times when complex logic needs thoroughly tested.  To do this I have built some software to help.  It all works through a ReflectionMockingManager class, which defines the object that will be mocked.  Here is a test that can mock the properties of a class.

Listing 1

[Test]
public void TestUserFieldAccess()
{
  User user = new User();
  user.Name = "Brian";
  ReflectionMock userMock = ReflectionMockingManager.MockObject(user);
  FieldDefinition prop = userMock.Field("Name"typeof(string));
  Assert.AreEqual("Brian", prop.GetValue < string > (user));
  Assert.AreEqual("Ted", prop.MockGetValue < string > (user, "Ted"));
  Assert.AreEqual("Jimmy", prop.MockGetValue < string > (user, "Jimmy"));
}

It has some usefulness because you can mock the test values returned are equal to the value you specify and that value is used in the business logic to see if the remaining logic works.  For instance, you can set property values even if they are not public "injecting" of a value into the object.  However, when trying to mock a list that was returned from the database provider, a SQL Exception is thrown because the DAL provider code is not actually mocked.  So the following test fails for that very reason.

Listing 2

[Test]
public void TestGettingUsers()
{
  List < User > usersList = new List < User > ();
  usersList.Add(new User("Brian", "b@gmail.com"));
  usersList.Add(new User("Ted", "t@gmail.com"));
 
  ReflectionMock mock = ReflectionMockingManager.MockObject < UserProvider > ();
  UserProvider provider = new UserProvider();
 
  User[]mockedList = mock.Method("GetUsers"typeof(User[])).MockReturnValue <
    User[] > (provider, usersList.ToArray());
  Assert.IsNotNull(mockedList);
  Assert.AreEqual(2, mockedList.Length);
}

This is why something more is needed, above and beyond simple reflection, because reflection does not have the ability to alter whether the method runs or not, and setup expectations for the method.

Mocking Frameworks

Mocking frameworks provide an added ability over reflection and the code you have just seen.  There are freely-available mocking frameworks available online.  Some mocking frameworks are interface-based, meaning that you need to use an interface to define the object.  The framework this article is going to demo is TypeMock.  TypeMock has the ability to mock an entire class, its properties, and methods.  This means that you could mock a data layer, a business class, or any other object you desire, and it has the ability to do this by dynamically intercepting the call to it and instead returning the mock.

TypeMock also features the ability to inspect the operation of a method, ensuring that everything works as normally expected.  Because you can change the internal value, you have the ability to mock the returned value from a method call inside a method, and therefore perform more strenuous testing on an object.  This allows you to test your methods more in-depth and get more specific with your unit tests.  Rather than explain all the details, let us look at an example.  To work with mocks, the MockManager must be used.  MockManager must call Init() before running tests and must call Verify() to verify the tests.  These calls usually occur in the setup and teardown methods in an NUnit test.

Listing 3

[TestFixtureSetUp]
public void Initialize()
{
  MockManager.Init();
}
 
[TestFixtureTearDown]
public void Shutdown()
{
  MockManager.Verify();
}

So let us work with objects and setup some expectations.  The code sample attached uses a business and data layer. To obtain a mock, all we need to do is the following.

Listing 4

Mock _gatewayMock = MockManager.MockAll(typeof(UsersDataGateway));

Because we have a mock, we will still need to instantiate the object somehow; however, because UsersDataGateway DAL class is used in the business layer, that instantiation will suffice.  All instances of the DAL layer are mocked.  There is also a MockManager.Mock method that mocks a class one time.  Now that we have our mock, we can setup expectations, mock returned values, test unexpected exceptions, or let the original method be called.

Below are several expectations defined in later unit tests. The expectation expects a certain method to be called and mocks the desired result. There are other methods that you can use like ExpectCall, just to verify that a method exists.

Listing 5

_gatewayMock.ExpectAndThrow("GetDatabase", new InvalidCastException(), null);
_gatewayMock.ExpectAndReturn("GetDatabase", nullnull);

In addition, you can use the ExpectGet and ExpectSet methods to perform property expectations as well.  For a full reference to the possible expectations, please see the TypeMock documentation.

Take a look at the following unit tests.

Listing 6

[Test]
public void TestMockingDAL()
{
  UserProvider provider = new UserProvider();
  _gatewayMock.ExpectAndThrow("GetDatabase"new InvalidCastException(), null);
  try
  {
    provider.AddUser("Test", "test@gmail.com");
    Assert.Fail("Invalid cast exception should be thrown");
  }
  catch (InvalidCastException ex){}
  _gatewayMock.ExpectAndReturn("GetDatabase"nullnull);
  try
  {
    provider.AddUser("Test", "test@gmail.com");
    Assert.Fail("Null exception should be thrown");
  }
  catch (NullReferenceException ex){}
}

The tests above are ensuring that with the expectations and mocked value, the right result occurs.  In addition, you can mock the results that are returned from a method.  The following is a test for mocking the GetUsers() method, which mocks the DataTable returned.  The method passes in a predefined one that is more useful for unit testing the creation of the Users array.  So, when calling GetUsers for the data provider, the real method does not run and the fake object is returned.

Listing 7

[Test]
public void TestUsingDAL()
{
  UserProvider provider = new UserProvider();
  DataTable resultsTable = new DataTable();
  resultsTable.Columns.Add("Name", typeof(string));
  resultsTable.Columns.Add("Email", typeof(string));
 
  DataRow resultsRow = resultsTable.NewRow();
  resultsRow["Name"= "Brian";
  resultsRow["Email"= "brian@gmail.com";
  resultsTable.Rows.Add(resultsRow);
 
  resultsRow = resultsTable.NewRow();
  resultsRow["Name"= "Ted";
  resultsRow["Email"= "ted@gmail.com";
  resultsTable.Rows.Add(resultsRow);
 
  resultsRow = resultsTable.NewRow();
  resultsRow["Name"= "Jerry";
  resultsRow["Email"= "jerry@gmail.com";
  resultsTable.Rows.Add(resultsRow);
 
  _gatewayMock.ExpectAndReturn("GetUsers", resultsTable, null);
  User[]users = provider.GetUsers();
  Assert.IsNotNull(users);
  Assert.AreEqual(3, users.Length);
  Assert.AreEqual("Brian", users[0].Name);
  Assert.AreEqual("Ted", users[1].Name);
  Assert.AreEqual("Jerry", users[2].Name);
}

In these examples I do not actually do anything against the database; all of this is done through mocking, which I either do not actually run the command code or mock the returned DataTable when retrieving users.  That is the power of mocking and this framework, in that you can control testing to that level.

Some Considerations of Mocking Libraries

Mocking libraries are great; however, some require additional requirements to use this library.  With installing TypeMock or TestDriven.NET, TypeMock will work when unit testing with in Visual Studio, by setting the startup program to the NUnit application.  However, running NUnit independently requires that some startup functions occur via script, which these instructions are available on the web site.  There is a Visual Studio Add-In that TypeMock uses, which is why you do not need to configure anything when running the project in the editor.  For running instructions, view the TypeMock web site.

Downloads
References
Conclusion

In this article you learned how to perform mocking in unit testing using TypeMock with the help of examples.



©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-29 4:43:29 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search