Based off the example that you are having us imagine, the simple answer to your question is your approach is not correct. By having the trouble you are experiencing, the code is trying to tell you that you have some mixed concerns in the code that are coupled too tightly together, and that instead of having cohesive code, you are having adhesive code. (Glenn Vanderburg has a nice blog entry on the topic of cohesion found at http://www.vanderburg.org/Blog/Software/Development/cohesion.rdoc)
If you are feeling the need to mock out MethodA
and MethodB
to test MethodC
this is a signal that one of a few things, possibly all of them even, are missing in the code.
The first thing the difficulty is telling you is that MethodC
may likely be in the wrong location in the code. MethodC
may very well belong to another object which takes and object with MethodA
and MethodB
as a dependency, either through constructor injection, or parameter injection.
The second thing that stands out, is that you are having trouble testing MethodC
because MethodB
has a dependency on what would lead me to think of being a global/singleton behavior. You have defined MethodB
as returns a random number
, instead of taking a dependency on a object that fills a role of NumberGenerator
. By explicitly calling out the dependency on this role (Interface), it would allow you to pass in different implementations of the role depending on the usage. Three obvious implementations that could be used and easily swapped out depending on if it is production code or test code would be:
- a
RandomNumberGenerator
: returns a random number every time it is called,
- a
SequentialNumberGenerator
: returns the next number in a sequence (of which multiple types of sequences could be generated), such as increasing by a set number every time, or some kind of a mathamatical sequence, e.g. Fibbonacci or Collatz
- a
ContsistantNumberGenerator
: returns the same number every single time it is called, which is very useful in testing.
The third thing that your example may be telling you is a refinement of the previous issue, calling out that you have a dependency on not only mutable state which you can't control, but non-deterministic mutable state, which you would have no means of coercing into a given state, even by sending a number of other messages to objects to try to get into that state. I know of no messages that you can send that will setup the environment to return a desired random number upon the next call to get it; even if there is such a way, the amount of setup that would be required would obscure what you are actually trying to test.
I hope that one of these suggestions help you address your issue.