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
0 votes
I've been using TypeMock for a while now. One feature I find myself longing for over and over is the ability to set an expected method call and call another method to do the work. In other words rather than returning a static value or just recording that the call was made, dispatch to another method to let me do some processing.

With TypeMock I can test a method like this:

public static int AddUser ( string name, string password,
string loginParameter, IdentityType identityType, int siteId )
{
AuthorizationManager.EnsureCurrentUserIsAuthorized (
KnownPrivileges.ProfileAdministrator );

return DbGateway.AddUser ( name, password, loginParameter,
identityType, siteId );
}

and get 100% code coverage by setting up expectations for the call to AddUser and checking all the parameters. But what I find myself desiring more and more is to test the contract of this class by calling AddUser, DeleteUser, & UpdateUser and testing the results.

I know that one way to do this is to refactor the code above and have a DbGateway that works for a real SQL database and a mock one that is only used in testing that reads/writes to a DataSet. But this is a simple class. In a large class that has a complex contract this can be difficult to pull off with existing code. If I were to write this code over from scratch I would start with testability in mind.

What I would like is something like this:

public static class MockedDbGateway {
public static AddUser ( string name, string password, string
loginParameter, int identityType, int siteId ) {
//Write this user to a DataSet
}

public void AssertData() {
//Run some assertions to make sure the DataSet reflects what you
//expect.
}
}

public TestAddUser() {
using (RecordExpectations recorder =
RecorderManager.StartRecording()) {
recorder.ExpectAndDispatch(
DbGateway.AddUser ( name, password, loginParameter,
identityType, siteId ), MockedDbGateway.AddUser);
recorder.
}
MockedDbGateway.AssertData();
}

Hope that kind of gives you an idea of what I'm thinking of. Another way would be to have a way for MockManager to return a specific type of mock (say MockDbGateway). Then you could use reflection to map the methods of the MockDbGateway onto the methods of DbGateway. That would be pretty powerful as well, and maybe easier to implement.
asked by ksummerlin (4k points)

4 Answers

0 votes
Interesting request,
I hope that I understand it fully.
But wouldn't Dynamic Return Values help?

E.G.
[Test]
public TestAddUser() {
  using (RecordExpectations recorder = RecorderManager.StartRecording()) 
  {
      DbGateway.AddUser (name, password, loginParameter,
         identityType, siteId);
     recorder.Return(new DynamicReturnValue(CallMockAddUser));
  }
  // Rest of test
}

private object CallMockAddUser(object[] parameters, object context) 
{
   return MockedDbGateway.AddUser(parameters[0],parameters[1],
      parameters[3],parameters[4],parameters[5]);
}

or just put the MockedDbGateway.AddUser code in the CallMockAddUser method.

Is this good enough? Am I missing something?
answered by scott (32k points)
0 votes
I was aware of this delegate and I've used it in situations where I need a next id value (i.e. return i++). But I can't find a similar type of class or delegate for a function that does not return a value. In my case it would be the void Delete(int id) method.

I thought about using a custom Parameter checker to do this, but it just "smells" wrong.
answered by ksummerlin (4k points)
0 votes
I guess that this is not well documented. We will have to change that.
TypeMock will ignore the return value for void methods (unless it is CONTINUE_WITH_METHOD)

Here is the delegate
private object CallVoid(object[] parameters, object context)
{
   MockedDbGateway.AddUser(parameters[0],parameters[1],
      parameters[3],parameters[4],parameters[5]);
  return null;// this is ignored as the mocked method is void
}
answered by scott (32k points)
0 votes
This works great. I'm very happy with the way this works, now that I fully understand it.

I love this tool more and more every day.
answered by ksummerlin (4k points)
...