Monday, February 4, 2008

Creation of Mocks - On the difference between Mock and MockObject

One of the most confusing points when dealing with Typemock Isolator is the creation of Mock Controllers (the term Mock controller refers to the object which is used to define the behavior of the mocked object during the test). When creating these controller there are two sets of API one can use:

  1. MockManager.Mock
  2. MockManager.MockObject

The difference between the two is quite simple: to

Using the Mock API tells the framework to attach the created Mock Controller to the next instance that will be created (in the future). This means that the next time a new call will be issued for the given type, a Mock Controller will be attached to the created instance which will cause all calls on that instance to be mocked.

Using the
MockObject API tells the framework to create a Mock Controller and an instance of that type and attach them to one another. The real instance that is mocked is created immediately and it can be accessed through the MockObject.Object property.

So when to use which?

The
Mock API is used when the creating of the instance we wish to mock is done internally in the tested class and we have no convenient way of accessing it.

The
MockObject API is used when the instance we want to mock is created outside the tested class and is passed to it. The nice thing about the MockObject API is that unlike the Mock API it can handle types that usually cant be instantiated such as interfaces & Abstract classes

Another related issue which usually goes hand in hand with the usage of these API's is the handling of Unexpected Calls (we refer to calls which have no expectations set on them as Unexpected Calls).

When using the Mock API we always mock concrete classes, for which all methods have real implementation. By default when mocking these types all Unexpected Calls will be directed to the real code. In most cases this is the intent of the user.

When using the
MockObject API, more often we mock Interfaces/Abstract classes. And since for these not all methods have real implementation, by default issuing an Unexpected Calls will result in an exception being thrown. From our experience Unexpected Calls in these cases indicates a logic flaw in most cases.

(There are some cases in which the MockObject API is used to mock concrete classes, in these scenarios the behavior is the same as if using the Mock API since the actual default is determined by the type of the class being mocked and not by the API itself)

10 comments:

Paulo Morgado said...

How about static class members? Can I mock only static members without mocking instances?

Royo said...

Paulo, can you give an example?

Paulo Morgado said...

Just imagine you some kind of singleton:

public class MyClass
{
public static Current { get; set; }

// instance members
}

Can I mock MyClass.Current without mocking the next instance?

Royo said...

Paulo: yes. that is possible with the new beta:
"Static members can also be mocked using the CallStatic.MockField API."

http://www.typemock.com/Docs/UserGuide/Fields.html

ulu said...

I like the term "Mock Controller" -- it's much more clear than just Mock. When I started learning TypeMock, it took me some time to realize the difference.

Paulo Morgado said...

"Using the Mock API tells the framework to attach the created Mock Controller to the next instance"

If I call MockManager.Mock< MyClass >() to mock the static filed, the next instance will be mocked, right?

Lior Friedman said...

Paulo, I think you are on to something.
However, if youll be carefull I dont think its really matters (and if by any chance it is, you can set static expectations on objects created using the MockObject API)

Thomas Eyde said...

What do I do when the Unexpected Call exception is called, and my logic is not flawed?

Also, wouldn't it be better if the exception were thrown only when MockManager.Verify() is called?

My deal is that I:
- pass the mocked instance to my constructor in the [Setup] method (I use NUnit)
- I have several tests that triggers a call to the mock, but they aren't meant to verify this.
- Only one of my tests are supposed to actually verify this call.

However, I can't figure out how to make the mock to ignore the unimportant calls.

I guess I could extract that single test to a new test class, but that defeats the purpose of TypeMock, doesn't it? Now I have to design my (test)code to be testable.

But that would still not solve my problem. I still have to pass a stub to my constructor.

Thomas Eyde said...

Please except my apologies on this one. This is how it ends when my peer is me :(

I somehow managed to create the mock controller twice, and used the mocked instance from the erroneous one.

Eli Lopian said...

Actually, Thomas your question is valid.
Here is how you can make sure that
1. Verify doesn't fail the test: Advanced Stubs with Natural Typemock™
2. Verify of arguments are postponed Postponing Argument Validation