Mocking Adventures with NMock2: Stubs Advanced

NMock2 is a library for assisting test driven development of .NET code by providing a dynamic mock object creation framework.

In my last post on NMock2, I introduced the new Stub feature of NMock2 and its basic usage. In the second part, we are going to have a look at the advanced possibilities of the Stub mock style:

  • Define Mock Style Of Nested Mocks
  • Define Default Values

Define Mock Style Of Nested Mocks

We have seen in the first part that NMock2 creates automatically new mocks as return values for interfaces and classes (for expectations see first part). These mocks have per default a mock style equal to Stub. Therefore, they behave as their parent and calls to methods or properties will be handled the same way – by returning default values.

There are however scenarios when you want to have more control on what is called on a nested mock. One way is to use Expect.Never.On(nestedMock) to guarantee that a member isn’t called. Or to override each possible call with other expectations. The more flexible way is to override the mock style that is used to create the nested mock:

mockery.SetStubMockStyle<NestedType>(mock, MockStyle.Default);

The above example shows how to override the mock style to MockStyle.Default for all properties, methods and indexers of the mock mock that return a value of type NestedType.
The result is, that the return value is a mock that will react with UnexpectedInvocationExceptions when a member is called and no expectations were set.
As you can see, you can define the mock style per mock instance and type.

If you want to set it for a single member of the mock then use a normal expectation on that member and set the desired nested mock as return value in the return action:

var nestedMock = mockery.NewMock<NestedType>(MockStyle.Default);
Expect.Once.On(mock).Method("GetNested").Will(Return.Value(nestedMock));

The last option is to define the mock style used by a Stub for all return types at once:

mockery.SetStubMockStyle(mock, MockStyle.Transparent);

You can define multiple mappings per mock and you can override mappings, too:

mockery.StStubMockStyle(mock, MockStyle.Transparent);
mockery.SetStubMockStyle<NestedType>(mock, MockStyle.Default);
mockery.SetStubMockStyle<AnotherNestedType>(mock, MockStyle.Default);

The result of this is that all created nested mocks of type NestedType and AnotherNestedType have a mock style equal to Default and all other nested mocks have a mock style equal to Transparent.

Define Default Values

You have seen in the first part of my NMock2 Stub discussion that mocks with a mock style equal to Stub will return default values for return types:

  • string → emtpy string
  • value types → the default value of that type (e.g. 0 (zero) for ints, doubles, false for booleans)
  • classes implementing IEnumerable → instance created with default constructor
  • sealed classes → null
  • all other classes and interfaces → nested mock

If you want to change this behavior then you can register a so called type resolver with the mockery:

mockery.SetResolveTypeHandler(
   delegate(object mockInstance, Type requestedType)
   {
      if (mockInstance == (object)mock && requestedType == typeof(int))
      {
         return 5;
      }

      return Missing.Value;
});

The type resolver gets the mock on which the call is made and the return type of the called member passed in as arguments. You can return the value that should be returned by the mock depending on these two pieces of information. Be aware that you should use this feature only if there are multiple members in the mock for which you want to setup the default value; otherwise it would be easier to just define an expectation on the mock. It can however be very handy if you want  to return for example an non-empty list for all members returning an IList.

The Missing.Value is used to signal that the mockery should use the default type resolver that will use Stub as mock style.

That’s it for now about the new Stub feature.Please keep in mind that this is all unreleased stuff and therefore may change until the next official release.

Next time, I’ll show you the new way of defining mocks that allows for example to define mocks that implement several interfaces. In the mean time, I’d be glad to answer your comment.

About the author

Urs Enzler

Add comment

By Urs Enzler

Recent Posts