Is this (unit) testing approach correct?
If you're wanting to mock out dependencies so you can test a specific unit of your code (e.g. MyClass
in your example), then you need to look at composing your code into services that take care of the different responsibilities. In your example your MyMethod
has several responsibilities:
- Creating a new
MyContainer
- Creating a new
FooClass
- Providing the
MyContainer
instance that FooClass
should be created with.
To satisfy your desire to test that MyMethod
passes a particular MyContainer
into the FooClass
you could separate responsibilities 1 and 2 out into new classes. Typically, in C#, you would give these classes an interface and have MyClass
take each of these interfaces as a dependency. E.g.
public interface IFooClassProvider
{
FooClass CreateFooClass(MyContainer container, int d, int e, int f);
}
public interface IMyContainerProvider
{
MyContainer CreateMyContainer(int a, int b, int c);
}
public MyClass
{
private IMyContainerProvider _myContainerProvider;
private IFooClassProvider _fooClassProvider;
public MyClass(IMyContainerProvider myContainerProvider, IFooClassProvider fooClassProvider)
{
_myContainerProvider = myContainerProvider;
_fooClassProvider = fooClassProvider;
}
...
public bool MyMethod(int a, int b, int c, out FooClass foo)
{
var someContainer = _myContainerProvider.CreateMyContainer(a,b,c);
foo = _fooClassProvider.CreateFooClass(someContainer,1,2,3);
...
return true;
}
...
}
Hopefully the 'real' implementations of the interfaces are obvious. In order to perform your test, you can then create mocks for each of these interfaces, e.g. new Mock<IFooclassProvider>()
and pass them into the constructor for MyClass
. In your unit test you can Setup
the IMyContainerProvider
mock to provider a specific container instance that you create in your unit test. You can then Verify
that the IFooClassProvider
mock's method was called with the specific container.
E.g.
var mockFooClassProvider = new Mock<IFooClassProvider>();
var mockMyContainerProvider = new Mock<MyContainerProvider>();
var myKnownContainer = new MyContainer(...);
mockMyContainerProvider.Setup(m => m.CreateMyContainer(It.IsAny<int>, ...))
.Returns(myKnownContainer);
var myClass = new MyClass(mockMyContainerProvider.Object, mockFooClassProvider.Object);
FooClass fooClass;
myClass.MyMethod(..., out fooClass);
mockFooClassProvider.Verify(m => m.CreateFooClass(myKnownContainer, It.IsAny<int>(),...);
This answer is taking things to an extreme for such a simple situation, but I figure the example in the question was a simplified version of some more complex code. Separation of responsibilities in this fashion quickly simplifies code into short testable segments.