- Part 1: Why use it?
- Part 2: Write My Tests First?
- Part 3: Keys to Effective TDD
- Part 3, Key #1: Write Testable Code
- Part 3, Key #2: Write Good Tests
- Part 3, Key #3: Using Fakes and Dependency Injection
- Part 4: Conclusion
As mentioned earlier, we need to be able to use Dependency Injection so we aren’t testing more than one thing. And if we don’t want to test more than one thing, that means we’ll have to “inject” same fake objects.
Using Fakes (or Mocks as many people refer to them) was one of those things that took me a while to understand.
When I first started TDD, I would create my own “mock” classes, like a mock repository that would return real data. In the mock class, I would essentially build up an in-memory database that I could then query and return data from. Needless to say, that was a huge pain and was not maintainable.
Then I started reading about mocking frameworks. But still I didn’t get it. “They don’t do anything, what’s the point?” But that is the point, we don’t want them to do anything. They are just there to either allow our code to run, or so we can verify that they were utilized correctly.
Here is a sample test checks to see if our PrintInvoice() method calls the repository like it should (using Moq as the mocking framework):
This might seem a little crazy so let’s break it down.
- First of all, notice the Arrange, Act and Assert sections. I like to put this in each of my tests to remind me that my test has 3 parts. First, setup the test scenario. Then perform some action – this is what we’re actually testing. Finally, verify that what we expected to happen actually happened.
- In the Arrange section, I’m setting up four Fake objects. These will be passed into the InvoicePrinter constructor so we can perform our tests. Keep in mind, these objects are fake and don’t really do anything, they’re just there so we can run our test and verify that it worked.
- The Assert line might be a bit confusing – it was for me at first. But really it’s saying “verify that my mock repository object had it’s FetchOrder() method called exactly once, and that the value passed into it was 1234.”
Fakes, Mocks, & Stubs?!?
As Martin Fowler put it, mocks aren’t stubs! So what are mocks, stubs, and fakes – and what difference does it make? Here’s a short explanation of each:
- Fake == a generic term for Mocks & Stubs
- Mock == a Fake that is used to verify something
- Stub == a Fake that is just a place holder so your code can run
So in the example above, the repository object was a Mock. That’s because we verified that some certain behavior on that object was invoked. The other Fakes in that method are all Stubs – they’re just there so our test can run.
Let’s say we have this class:
As you can see we are using Dependency Injection for our ILogger. This allows us to test just our SalesTaxCalculator class without worrying about the concrete implementation of ILogger.
But what about our “real” code? At some point we need to create a concrete implementation of the ILogger interface and get it into our class, right?
There are a couple of ways we could do this. We could have another constructor that doesn’t take any arguments and defaults _logger to our real Logger class. But that’s a little smelly – we are technically still coupled to that Logger class in some way.
Another way to do it is to use an Inversion of Control Container (IoC Container). These are utilities that allow you configure what the default implementation of a given interface is. Then, when that interface is required, the IoC container will give you an instance of the default.
For example, here is what a Castle Windsor configuration might look like for our ILogger interface:
This tells Castle: “Anytime I’m looking for an ILogger, give me a Logger. By the way, ILogger and Logger are both in MyApp.dll under the MyApp namespace.”
So if we are configured to use IoC, we don’t have to change our SalesTaxCalculator class at all. The IoC container will just give us the correct concrete class any time we need one.
Simone Busoli has an awesome four part article on using Castle Windsor.