Doing Outside In development is important. You will be able to better design your classes when dealing with use cases or stories.
Imagine you have a notebook, when you turn it on, you also need to turn on its monitor and keyboard.
Let’s write some acceptance tests for this.
Let’s try to implement the acceptance spec starting with Notebook:
Hum, of course it will fail for many reasons. First, we need Monitor and Keyboard classes and they need to respond to #turn_on. We need two already implemented classes just to start writing our Notebook class!
Dependency Injection to the rescue!
Dependency Injection is very discussed in programming development for decoupling code. In Ruby we feel like we get it for free. It improves our code design by decoupling classes and eases our tests.
So, let’s start writing unit tests for Notebook with Dependency injection.
Nice! We didn’t need Monitor and Keyboard classes to write our Notebook code! We can test everything in isolation because we’re able to stub our methods/constructors inputs, so we won’t need the actual objects.
Remember, Ruby is a very powerful dynamic language. It doesn’t care about type, only about their interfaces. If a Monitor and an ExpensiveMonitor behave like the same for the computer needs, it will work.
Our unit tests for Notebook are green now! Yay! Look, we don’t use Monitor or Keyboard objects, we use stubs, so you need to pay attention to some points. Look at the #as_null_object I added in monitor and keyboard stubs. It’s needed because our stubs don’t respond to #turn_on.
Each expectation mocks the #turn_on in a SINGLE object and expects it. But the other doesn’t respond to it, so each test would fail because of the other dependency.
Using #as_null_object, we tell the stub to respond to any method in any test, so it won’t break other tests so each test will have only one expectation.
So our Notebook works as expected, but our acceptance test is still red because we don’t have Monitor and Keyboard.
And our monitor and keyboard:
Now our unit and acceptance tests are green. We did Outside In development and improved our unit tests with Dependency Injection. We didn’t need Monitor and Keyboard at first to test our Notebook.
This is a silly example but in the real world our classes have many dependencies and if we begin writing things the Inside Out way, we will write more code than we need.
You can start Outside In development from acceptance UI tests until the core of your application’s unit tests so you won’t loose yourself writing code you don’t need, and Dependency Injection will help you develop your project step by step, making you happier and your life easier.