tags:

views:

85

answers:

1

I am using an interface (IDataSet) in front of System.Data.DataSet for testing purposes. I want to be able to mock the Copy() method. Basically I want a copy/clone of the same mocked object.

Here's some pseudo code of what I would like to do.

Mock<IDataSet> dataMock = new Mock<IDataSet>();
Mock<IDataSet> copyMock = ???    // How do I clone the mock?

dataMock.Setup(c => c.Copy()).Returns(copyMock.Object);

Is this possible?

+3  A: 

Basically, a Mock is not the real thing, so it does not have real behavior. It's not supposed to have real behavior - it's supposed to do whatever you tell it while keeping track of what happened. Nothing more and nothing less.

This means that you have to tell it how its Copy method works. If you do the following, that's the implmementation the Copy method will have:

Mock<IDataSet> dataMock = new Mock<IDataSet>();
Mock<IDataSet> copyMock = new Mock<IDataSet>();

dataMock.Setup(c => c.Copy()).Returns(copyMock.Object);

However, you can also do this:

Mock<IDataSet> dataMock = new Mock<IDataSet>();
Mock<IDataSet> copyMock = dataMock;

dataMock.Setup(c => c.Copy()).Returns(copyMock.Object);

and that, then, becomes the implementation of the Copy method. Remember: an interface is not a contract that states what the method should do; it only defines the signature of methods.

You were probably hoping to copy data from one IDataSet to another, but remember that a Mock is pure behavior; it has no data.

A couple of alternatives you can think about are the following:

  • Replace IDataSet with an abstract DataSetBase class, and implement the Copy method like you want it to behave (that is, not as an abstract or virtual method).
  • Instead of creating a Mock of IDataSet, use a Fake. A Fake is a a test-specifict implementation of an interface that has behavior close to the real thing. There are no frameworks/libraries for creating Fakes, so you would need to code such a Fake by hand.
  • Consider whether the Copy method should really be part of the interface. It sounds to me like it's an implementation detail that doesn't belong on the interface in the first place.

You can read about Stubs, Mocks, Fakes and other unit testing design patterns in the excellent book xUnit Test Patterns.

Mark Seemann
Thanks for your insight. Switching "dataMock" to a Fake got me out of the cul-de-sac I was in.
magnifico
+1 - nice answer! I would argue that Moq allows you to create Fakes, since you can do Returns(Func) or Callback(Action). But a manual Fake may be more readable.
TrueWill
@TrueWill: That's a valid point, but most importantly it demonstrates a point I made in another context: Test Doubles inhabit a vaguely defined continuum: http://msdn.microsoft.com/en-us/magazine/cc163358.aspx
Mark Seemann