You should let the call to M1
pass through to a real instance of the M2
method.
In general, you should be testing the black box behaviour of your classes. Your tests shouldn't care that M1
happens to call M2
- this is an implementation detail.
This isn't the same as mocking external dependencies (which you should do)...
For example, say I have a class like this:
class AccountMerger
{
public AccountMerger(IAccountDao dao)
{
this.dao = dao;
}
public void Merge(Account first, Account second, MergeStrategy strategy)
{
// merge logic goes here...
// [...]
dao.Save(first);
dao.Save(second);
}
public void Merge(Account first, Account second)
{
Merge(first, second, MergeStrategy.Default);
}
private readonly IAccountDao dao;
}
I want my tests to show that:
Calling Merge(first, second, strategy)
results in two accounts getting saved that have been merged using the supplied rule.
Calling Merge(first, second)
results in two accounts getting saved that have been merged using the default rule.
Note that both of these requirements are phrased in terms of inputs and effects - in particular, I don't care how the class achieves these results, as long as it does.
The fact that the second method happens to use the first isn't something I care about, or even that I want to enforce - if I do so, I'll write very brittle tests. (There's even an argument that if you've messed about with the object under test using a mocking framework, you're not even testing the original object any more, so what are you testing?) This is an internal dependency that could quite happily change without breaking the requirements:
// ...
// refactored AccountMerger methods
// these still work, and still fulfil the two requirements above
public void Merge(Account first, Account second, MergeStrategy strategy)
{
MergeAndSave(first, second, strategy ?? MergeStrategy.Default);
}
public void Merge(Account first, Account second)
{
// note this no longer calls the other Merge() method
MergeAndSave(first, second, MergeStrategy.Default);
}
private void MergeAndSave(Account first, Account second, MergeStrategy strategy)
{
// merge logic goes here...
// [...]
dao.Save(first);
dao.Save(second);
}
// ...
As long as my tests only check inputs and effects, I can easily make this kind of refactoring - my tests will even help me to do so, as they make sure I haven't broken the class while making changes.
On the other hand, I do about the AccountMerger
using the IAccountDao
to save accounts following a merge (although the AccountMerger
shouldn't care about the implementation of the DAO, only that it has a Save()
method.) This DAO is a prime candidate for mocking - an external dependency of the AccountMerger
class, feeling an effect I want to check for certain inputs.