Mocks on the other hand are the mechanism that assuresthat tests focus on the unit/component being tested and not the components that thisunit interacts with. When the tested code uses other componentsthings can get quite fragile and the tests will quickly become system tests. Examplesare classes that use a database, a logging system, web service and any other externalcomponents. These external components might require a complex setup.For example, in order to run a test that uses a database, we must have a running databasewith the tables and data setup correctly for the test (we must cleanup this data beforeeach test runs). Too much work for a lazy developer,and more importantly test results easily compromised by factors that are out of ourcontrol.
So mocking in this case sounds like a validsolution. But what is the problem in implementing this in a CSLAworld? Well, CSLA has this concept of ‘Mobile Objects’, which meansthat the object is generally created in the (App) Server context, and then serializedto the client. For example let’s take a look at the way we retrieveProjectList object from the sample ProjectTracker20cs project.
/// <summary>Returna list of all projects.</summary>
public static ProjectList GetProjectList()
{
return DataPortal.Fetch<ProjectList>(new Criteria());
}
or,
/// <summary>Returna list of projects filtered by project name.</summary>
public static ProjectList GetProjectList(string name)
{
return DataPortal.Fetch<ProjectList>
(new FilteredCriteria(name));
}
For all of us that use CSLA daily this meansthat the DataPortal is going to instantiate the object of type ProjectList, call appropriateoverride of the method DataPortal_Fetch() definedin the ProjectList,and finally serialize it back to the client where that instance is returned troughthe factory method in question.
DataPortal_Fetch methodoverrides should resemble something like this:
private void DataPortal_Fetch(Criteria criteria)
{
//fetch with no filter
Fetch("");
}
private void DataPortal_Fetch(FilteredCriteria criteria)
{
Fetch(criteria.Name);
}
private void Fetch(string nameFilter)
{
RaiseListChangedEvents= false;
using (SqlConnection cn= new SqlConnection(Database.PTrackerConnection)){
cn.Open();
using (SqlCommand cm= cn.CreateCommand()) {
cm.CommandType= CommandType.StoredProcedure;
cm.CommandText= "getProjects";
using (SafeDataReader dr= new SafeDataReader(cm.ExecuteReader())){
IsReadOnly= false;
while (dr.Read()){
ProjectInfo info= new ProjectInfo(
dr.GetGuid(0),
dr.GetString(1));
//apply filter if necessary
if ((nameFilter.Length== 0) || (info.Name.IndexOf(nameFilter) == 0))
Add(info);
}
IsReadOnly= true;
}
}
}
RaiseListChangedEvents= true;
}
Now let’s take a look at how most of the mocking frameworksmock dependencies. Generally one needs to create an interface onthe object we are mocking, and then pass the reference to that interface to the objectwe are trying to test. This is essentially the implementation ofthe “Dependencyinjection pattern”, where the actual implementation is passed as this interfaceat run time, or mock object during the tests. This, as far as Ican tell, applies to NMock, EasyMock,or RhinoMock.
So the problem is that these mocking tools require us tobuild “mockable” objects. This will not work with CSLA, orat least will not be implemented easily. The problem is that, ifone wants to mock dependencies such as data access layer components (db connection,data reader, command) one would have to instantiate them on the client side and then“inject” them as arguments into the Factory Method being called, making sure thatthey are somehow serialized to the server side. And naturally databasecomponents are not serializable.
So, is it possible to mock CSLA dependencies thatreside only on server side and are not serialized back and forth? Theanswer is “Yes”. Yes if you use TypeMock.Net library. Whatis the major advantage of this tool when compared to other .Net mocking tools? TypeMockuses Aspect Oriented technology to redirect calls from the real code to the mock objectinstantiated. So how does this work?
Before we try to mock dependencies we have toremember one of the golden rules of Mocking: “Never to Mock classes/interfacesyou do not own or have source code to”. What does that mean? Ihave seen code where developers tried to Mock interfaces as IDataReader (or SqlDataReader)for example. That interface is too complex and it is not somethingI defined or have control over. So the first thing I would liketo do is build a class called Database, that encapsulates all of the database communicationin the Fetch() method. Solet’s do a little refactoring:
private void Fetch(string nameFilter)
{
RaiseListChangedEvents= false;
using (Database db= new Database(Database.PTrackerConnection)){
SqlCommand cm= db.CreateSPCommand("getProjects");
using (SafeDataReader dr= db.ExecuteSafeDataReader(cm)) {
IsReadOnly= false;
while (dr.Read()){
ProjectInfo info= new ProjectInfo(
dr.GetGuid(0),
dr.GetString(1));
//apply filter if necessary
if ((nameFilter.Length== 0) || (info.Name.IndexOf(nameFilter) == 0))
Add(info);
}
IsReadOnly= true;
}
}
RaiseListChangedEvents= true;
}
Let us compare the code above to the original Fetch(). Onecan notice that instead of creating SqlConnection object we created a Database objectpassing its constructor a desired connection string. You will alsonotice that we are not explicitly “Opening” database connection. Thatis because the Database class is managing SqlConnection internally and opening itas needed (for example, within the Database.ExecuteSafeDataReader() callas you might notice bellow when we take a look at the Database class).
In addition you will notice that we have removed the usingblock around the SqlCommand instance. Again the Database instancemanages SqlCommand objects it creates and disposes them at the time it is disposeditself (together with disposing a SqlConnection).
Below is a simplified version ofthe Database class. Some of you might notice s similarity to theDatabase class implemented in Enterprise Library. I do generallyuse Enterprise Library, and the pattern used in their Data Access Block makes it easierto test/mock DAL objects.
public class Database : IDisposable
{
private readonly SqlConnection _activeConnection;
private readonly List<SqlCommand>_createdCmds;
private bool disposed;
public Database(string connection)
{
_activeConnection= new SqlConnection(connection);
_createdCmds= new List<SqlCommand>();
}
~Database()
{
Dispose(false);
}
#region AvailableConnection Strings
public static string PTrackerConnection
{
get
{
return ConfigurationManager.ConnectionStrings
["PTracker"].ConnectionString;
}
}
public static string SecurityConnection
{
get { return ConfigurationManager.ConnectionStrings["Security"].ConnectionString;}
}
#endregion
#region IDisposableMembers
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed){
if (disposing){
//Dispose managed resources.
foreach (SqlCommand cmd in _createdCmds)
cmd.Dispose();
_createdCmds.Clear();
if (_activeConnection!= null && _activeConnection.State != ConnectionState.Closed)
_activeConnection.Close();
}
//Dispose unmanaged resources
}
disposed= true;
}
#endregion
protected void OpenConnection()
{
if (_activeConnection.State!=ConnectionState.Open)
_activeConnection.Open();
}
public SqlCommand CreateSPCommand(string cmdName)
{
SqlCommand cm= _activeConnection.CreateCommand();
cm.CommandType= CommandType.StoredProcedure;
cm.CommandText= cmdName;
_createdCmds.Add(cm);
return cm;
}
public SafeDataReader ExecuteSafeDataReader(SqlCommand cm)
{
OpenConnection();
return new SafeDataReader(cm.ExecuteReader());
}
public void AddWithValue(SqlCommand cm, string paramName, object value)
{
cm.Parameters.AddWithValue(paramName,value);
}
}
NUnit usesTest Fixture concept to group tests applied to a single unit of code. Sosince we are going to test the ProjectList object let’s create that Test Fixture:
[TestFixture]
public class ProjectListTest
{
[SetUp]
public void Start()
{
///<remark>InitializeTypeMock before each test</remark>
MockManager.Init();
}
[TearDown]
public void Finish()
{
///<remark>Wewill verify that the mocks have been called correctly at the end of each test</remark>
MockManager.Verify();
}
}
As you can see in order to use TypeMock inour tests we need to Initialize the TypeMock’s MockManager first and then call Verify() atafter the test has run.
Now we are ready to write our first test. Generallymy first test is something extremely simple like making sure that the operation returneda result. So the first test is going to be the one that ensuresthat the ProjectList.GetProjectList() createsand adds a single ProjectInfo object.
[Test]
public void LoadsOne()
{
ProjectList item= ProjectList.GetProjectList();
Assert.AreEqual(1,item.Count);
}
This first test does not have any mocks obviously, and ifwe run it we are going to see the following error:
ProjectTracker.Library.Tests.ProjectListTest.LoadsOne: Csla.DataPortalException : DataPortal.Fetch failed (System.NullReferenceException:Object reference not set to an instance of an object.
atProjectTracker.Library.Database.get_PTrackerConnection() in C:\Development\csla20cs\ProjectTracker20cs\ProjectTracker.Library\Database.cs:line37
atProjectTracker.Library.ProjectList.Fetch(String nameFilter) in C:\Development\csla20cs\ProjectTracker20cs\ProjectTracker.Library\ProjectList.cs:line73
atProjectTracker.Library.ProjectList.DataPortal_Fetch(Criteria criteria) in C:\Development\csla20cs\ProjectTracker20cs\ProjectTracker.Library\ProjectList.cs:line62)
---->Csla.Server.CallMethodException : DataPortal_Fetch method call failed
---->System.NullReferenceException : Object reference not set to an instance of an object.
The error above states that the line where we triedto call new Database(Database.PTTrackerConnection) faileddue to static property PTTrackerConnection trying to access external configurationfile to read a connection string. So we will need to mock thatcall. In addition we will need to mock the whole Database instance,since the Database object internally instantiates the SqlConnection (another externalresource not available to us for this unit test). So let us writethe code that does that.
[Test]
public void LoadsOne()
{
Mock mockDb= MockManager.Mock(typeof(Database));
mockDb.ExpectGet("PTrackerConnection", string.Empty);
mockDb.ExpectAndReturn("CreateSPCommand", null);
mockDb.ExpectAndReturn("ExecuteSafeDataReader", new SafeDataReader(GetDataReaderStub()))
.Args(null);
mockDb.ExpectCall("Dispose");
ProjectList item= ProjectList.GetProjectList();
Assert.AreEqual(1,item.Count);
}
private IDataReader GetDataReaderStub()
{
return new DataTable().CreateDataReader();
}
We have added few lines to our test. Thefirst line allows defines the object that we are going to mock. Followingfour lines define the behaviors of the Database objects that we are going to interceptand replace with our values that we need for the test, therefore taking the databaseout of equation. As we can see from line:
mockDb.ExpectGet("PTrackerConnection", string.Empty);
We are expecting a Property Get call on the propertycalled PTrackerConection and we want it to return a constant string.Empty. Thenwe are expecting a method call to “CreateSPCommand”to be called, and want our mock Database to return null (we do not care about theSqlCommand since the mock Database object is not going to be using it anyway). Followingline is where it gets interesting:
mockDb.ExpectAndReturn("ExecuteSafeDataReader", new SafeDataReader(GetDataReaderStub()))
.Args(null);
As you can see we expect that the call to ExecuteSafeDataReaderreturns Data Reader as defined in the GetDataReaderStub() method. Ifwe run the test now following will be the output:
NUnit.Framework.AssertionException: Expected:1
Butwas: 0
at NUnit.Framework.Assert.That(Object actual, IConstraint constraint, String message,Object[] args)
at NUnit.Framework.Assert.AreEqual(Int32 expected, Int32 actual, String message, Object[]args)
at NUnit.Framework.Assert.AreEqual(Int32 expected, Int32 actual)
at ProjectTracker.Library.Tests.ProjectListTest.LoadsOne() in ProjectListTest.cs:line42
Since the GetDataReaderStub() methodis supposed to return a IDataReader that is constructed from the empty DataTable,then the number of items in the ProjectList should be zero. Moreimportantly we have successfully mocked the data access layer code although our testis still failing (we want to ensure that our test inserts one item from mock Databaseinto the ProjectList). Proof of successful mock is the fact thatwe are not getting any ado.net exceptions when we run the test – meaning that allof the calls to the Database object are intercepted as we expected. Assuringthat test is successful will require us to modify the GetDataReaderStub() methodto create a DataTable with the signature that is expected in fetch method, and withthe number of the records that are expected in the result (1).
But before we do that let’s first clean the test code. Igenerally do not want to crowd the code in the actual test with bunch of the detailsof the internal mocks. In addition it seemsthat there will be a common pattern in the way we fetch records, so I believe we canextract the Mock calls to a helper method called MockDatabaseFetchCall(). Alsoif this is to be method that is shared between multiple Test Fixtures we should moveit outside of this Test Fixture. Let’s see how our code looks likeafter that refactoring.
internal class MockHelper
{
public static void MockDatabaseFetchCall(string connectionName, int noOfAddInParamCalls, IDataReaderStubFactory drFactory)
{
Mock mockDb= MockManager.Mock(typeof(Database));
mockDb.ExpectGet(connectionName, string.Empty);
mockDb.ExpectAndReturn("CreateSPCommand", null);
mockDb.ExpectCall("AddWithValue",noOfAddInParamCalls);
mockDb.ExpectAndReturn("ExecuteSafeDataReader",drFactory.GetDataReaderStub())
.Args(null);
mockDb.ExpectCall("Dispose");
}
}
We can see that the MockDatabaseFetchCall() methodhas 3 parameters. The necessity for the first parameter is dueto the fact that our Database object has two “connection string” properties: “PTrackerConnection”and “SecurityConnection”. Argument connectionName, allows us tospecify which of the two we will mock. We can see that the secondparameter is related to the new line in our method:
mockDb.ExpectCall("AddWithValue",noOfAddInParamCalls);
What does that line mean? The line states that weexpect a call to the method called AddWithValue() noOfAddInParamCalls times,and that we are going to ignore parameters or the return value. Wejust want to ensure that the calls are made. But the method AddWithValuedid not exist in our original definition of the Database class. Wehave added this method as a part of this last refactoring. Here is what it does:
public void AddWithValue(SqlCommand cm, string paramName, object value)
{
cm.Parameters.AddWithValue(paramName,value);
}
In some of the Fetch() methodswe want to pass parameters to the stored procedure that allow us to filter the datawithin stored procedure. Then our Fetch call signature changes. Foreach parameter there is an extra call to the AddWithValue() method.
Now let’s move onto the third parameter: IDataReaderStubFactorydrFactory. It is an interfacethat defines a single method:
internal interface IDataReaderStubFactory
{
SafeDataReader GetDataReaderStub();
}
Basically since MockHelper.MockDatabaseFetchCall() isa shared method, and every list object’s (BusinessListBase<T>, or ReadOnlyBase<T>)Test Fixture will have one or more IDataReader Stubs, I decided to implement themas an interface. Here is the implementation for our “one recordfetch” of the ProjectList:
public class ProjectListFetchOneDRStub : IDataReaderStubFactory {
public SafeDataReader GetDataReaderStub()
{
DataTable stubTable= new DataTable();
stubTable.Columns.Add("pk",typeof(Guid));
stubTable.Columns.Add("desc", typeof (string));
stubTable.Rows.Add(new object[]{Guid.NewGuid(),string.Empty});
return new SafeDataReader(stubTable.CreateDataReader());
}
}
As you can see we are actually generating a DataTablewith columns that match structure expected in ProjectList.Fetch() method. Inaddition we are generating a single row of data.
Taking all this into account our modified test code shouldlook like this:
[Test]
public void LoadsOne()
{
MockHelper.MockDatabaseFetchCall("PTrackerConnection",0, new ProjectListFetchOneDRStub());
ProjectList item= ProjectList.GetProjectList();
Assert.AreEqual(1,item.Count);
}
After running this test we can see that the test passes. Projectlist successfully fetches and inserts one item. Now this lookslike a lot of work for our first test, but note how easy it is to create future testsof this type. Let’s say we want to test the other path in creationof the Project List – ProjectList.GetProjectList(stringname).
[Test(Description= "DataReader returns 3 items but only one should beinserted, based on filter")]
public void LoadsThreeFiltersTwo()
{
MockHelper.MockDatabaseFetchCall("PTrackerConnection",0, new ProjectListFetchThreeDRStub());
ProjectList item= ProjectList.GetProjectList("test");
Assert.AreEqual(1,item.Count);
}
The main difference between this one and our firsttest, besides us calling the GetProjectList(“test”) withthe string argument is that we pass a different IDataReaderStubFactory implementation– ProjectListFetchThreeDRStub. Andthat class is defined as:
public class ProjectListFetchThreeDRStub : ProjectListFetchBaseDRStub {
public override SafeDataReader GetDataReaderStub()
{
DataTable stubTable= GetStubTable();
stubTable.Rows.Add(new object[]{ Guid.NewGuid(), "testis important" });
stubTable.Rows.Add(new object[]{ Guid.NewGuid(), "" });
stubTable.Rows.Add(new object[]{ Guid.NewGuid(), "thistest record will not be included" });
return new SafeDataReader(stubTable.CreateDataReader());
}
}
You will notice that I have followed my usual behavior andhave refactored ProjectListFetchThreeDRStub (when compared to original ProjectListFetchOneDRStub). Ihave extracted the code that instantiates a DataTable, and creates column structureinto a method called GetStubTable(). This method was moved intoa base abstract class called ProjectListFetchBaseDRStub, and both ProjectListFetchThreeDRStub,and ProjectListFetchOneDRStub now inherit from it. Here is thecode of the base class:
public abstract class ProjectListFetchBaseDRStub : IDataReaderStubFactory {
public abstract SafeDataReader GetDataReaderStub();
protected static DataTable GetStubTable()
{
DataTable stubTable= new DataTable();
stubTable.Columns.Add("pk", typeof(Guid));
stubTable.Columns.Add("desc", typeof(string));
return stubTable;
}
}
Second test also passes. Althoughthe we have a SafeDataReader with 3 rows only the first one has a Name that beginswith “test”.
We can use the same IDataReader Stub to construct the ProjectInfotests, like:
[TestFixture]
public class ProjectInfoTest
{
[Test]
public void AssureFieldsMapped()
{
SafeDataReader dr= (new ProjectListFetchOneDRStub()).GetDataReaderStub();
dr.Read();
ProjectInfo info= new ProjectInfo(
dr.GetGuid(0),
dr.GetString(1));
Assert.IsNotNull(info);
Assert.AreEqual(string.Empty,info.Name);
}
}
Again this is a rather simple test just to show youone of the possible patterns to use in BusinessBase<T> or ReadOnlyBase<T> tests. Onceyou have your object constructed from the Data Stub you can run tests that involvebusiness logic, state and behavior of the object.
One might notice that there was a possibility of mockinga DataPortal itself within ProjectList.GetProjectList() method. Twoimportant issues with that path are that first we would not be testing the code runningwithin the Fetch() method,and the necessity to change an accessibility of constructor of the ProjectList classfrom private to public (to have Mock DataPortal return an instance).
In future posts I will explore mocking of the portions ofthe code that perform DB insert/update/delete, as well as more efficient way of generatingIDataReader Stubs.
>>