Mocking in Unit Tests
page 4 of 8
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 35400/ 66

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.


View Entire Article

User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-26 3:36:03 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search