chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
Is there a way to retrieve instances of objects affected by a global mock? Consider the following statement:

Mock<SqlConnection> connectionMock = MockManager.MockAll<SqlConnection>();


I was hoping that the Mock<SqlConnection>.MockMethodCalled event would provide the instance of the object that was called. Is there a technical reason why this cannot be provided and if not is there a way I can access the object from inside that event?

Basically here is my situation -- we have a data binding library that makes binding to stored procedures and results sets easier. I want to mock away the database interaction. One of the problems with mocking this library is that it may save and reuse SqlConnection objects in a pool if there is a transaction involved. So I have to use a global mock. Here is the code I am using right now:

/// <summary>
/// Mocks a call to the database, setting an expectation for the specified
/// parameters to be provided. The mocked call will return the specified
/// result set.
/// </summary>
public static void MockWithResultSet(DatabaseCall callExpectations, ResultSet resultSet)
{
   Mock<SqlConnection> connectionMock = MockManager.MockAll<SqlConnection>();
   Mock<SqlCommand> commandMock = MockManager.MockAll<SqlCommand>();
   Mock<SqlDataReader> readerMock = MockManager.MockObject<SqlDataReader>();

   // Mock the call to the database and the result set
   connectionMock.ExpectSetAlways("ConnectionString").Args(callExpectations.ConnectionString);
   connectionMock.ExpectGetAlways("State", ConnectionState.Open);
   connectionMock.ExpectCall("Open");

   commandMock.ExpectSetAlways("CommandText").Args(callExpectations.Statement);
   commandMock.ExpectSetAlways("CommandType").Args(callExpectations.StatementType);
   commandMock.ExpectAndReturn("ExecuteReader", readerMock.MockedInstance);

   readerMock.ExpectGetAlways("FieldCount", resultSet.Columns.Count);

   for (int i = 0; i < resultSet.Columns.Count; i++)
   {
      readerMock.ExpectAndReturn("GetName", resultSet.Columns[i]).When(i);
   }

   for (int i = 0; i < resultSet.Rows.Count; i++)
   {
      readerMock.ExpectAndReturn("Read", true);

      for (int k = 0; k < resultSet.Columns.Count; k++)
      {
         readerMock.ExpectAndReturn("GetValue", resultSet.Rows[i][k]).When(k);
      }
   }

   readerMock.ExpectAndReturn("Read", false);

   // Mock the clean up methods
   connectionMock.ExpectAlways("Close");
   connectionMock.ExpectAlways("Dispose");
   commandMock.ExpectAlways("Dispose");
   readerMock.ExpectAlways("Dispose");
}


As you can see I am performing partial mocks on the ADO.NET objects. For instance, SQL parameters are actually set on the real object (this works fine). The problem is that I can't access the mock instance because I am using MockAll, but I'd like to perform some asserts on the contents of the SqlCommand.Parameters collection after the replay.

So bottom line -- is there any way to access mocked instances of objects if global mocks are used?

-Joe
asked by jcrivello (1.8k points)

3 Answers

0 votes
Hi Joe,

The short answer is no. The reason is that the mock controller for MockAll controls the behavior of the instances that were already created and the ones that will be. That means there's no single instance.

Now I have a couple of questions. First why use MockAll for SQLConnection? Do you have more than one in your unit tests? (Same goes for SQLCommand and SQLReader).

Second, you have expectations in your tests. That makes your tests fragile. By this I mean, any small change inside the code, will break the test.

What I suggest, if possible, and by that I mean you have tests in place - refactor. If your tests are try to see if the parameters are set correctly, you can extract all the database method calls into a single method that acceptes all the parametrs you want to check. Then you mock this method and check that the arguments were sent for it exactly.

This way you don't have to carry all these expectations with you, and you get an encapsulated piece of code, which is mockable.

What do you think?
answered by gilz (14.5k points)
0 votes
Unfortunately it is not possible to refactor our code in this way. The data access library I was referring to works like this:

1. You define a criteria object with properties or fields that will be bound to the parameters of a stored procedure or query declaratively (with attribute decorations).
2. You define a data object that will be bound to rows of the result set again declaratively.
3. At runtime, the data access library takes the name of the query and other associated information, the criteria object, and returns one or more bound data objects. This is all powered by System.Reflection.Emit.

The reason I am using MockAll is because the library must maintain it's own connection pool so that connection objects can be reused. I am aware that ADO.NET maintains it's own connection pool which reduces or eliminates the performance issues with "opening" a connection for each data access. The reason we must have a connection pool or at least some shared state between queries is because ADO.NET requires transactions to be executed against the same connection object, unless you want to use a distributed transaction (which we don't for performance reasons).

So the problem is that if we use Mock instead of MockAll, only the first query will work. The second will not recreate the SqlConnection object and will in fact reuse the previous shell of an object which was mocked but is no longer (so it will just bomb). We also pool SqlCommand objects.

So with MockAll everything works, except I can't use a partial mock to access the parameter collection on the SqlCommand object because I do not have access to the mocked instance.

Note: Since I posted the original message, I extended my code to mock SqlParameterCollection which allows me to do this anyways. It's just a lot more code than it needs to be.

My bottom line is this -- it may be very useful in certain circumstances to provide the object instance being called to the MockMethodCalled event (when MockAll is being used).

I understand the expectations concern, we are still deciding what we want to do in that respect. That may be changed.

Thanks for your response.

-Joe
answered by jcrivello (1.8k points)
0 votes
And to clarify.. it would be possible to wrap our data access library in a "Data Access Layer" which would be mockable in the way you are referring to. However, I think one of the most powerful things about Typemock at least for our organization is that you are able to mock architectures that were not designed with testability in mind.

So yeah we could refactor, but then again if we were going to spend the ***** to do that we could always just use Rhino Mocks. :D

-Joe
answered by jcrivello (1.8k points)
...