14

I learned to do Test Driven Development (TDD), Dependency Injection (DI) and Inversion of Control (IoC) all at the same time. When I write code using TDD I always end up using DI in my class's constructors. I am wondering if this is because of how I learned to do TDD, or if this is a natural side-effect of TDD.

So my question is this: Does following TDD principals and writing unit tests that do not depend on external services inevitably lead to DI?

3
  • 8
    I'm reading The Art of Unit Testing and and it seems that it definitely does lead to Dependency Injection (DI).
    – programmer
    Aug 15, 2012 at 15:07
  • 2
    So what language is this about? DI/etc are necessary in Java, but that's because of a language limitation - languages like Python don't need it since they can monkey patch dependencies in the tests.
    – Izkata
    Aug 15, 2012 at 19:26
  • @Izkata: I agree that DI is a workaround for a language limitation; but monkeypatching isn't necesarily the same thing in less rigid languages. Among other ways I'd prefer first-class functions, which allows you to do naturally what DI approximates by discipline.
    – Javier
    Aug 15, 2012 at 22:39

5 Answers 5

19

Does following TDD and writing unit tests that do not depend on databases or external services inevitably lead to DI?

For wide definitions of DI, yes. Classes do not exist in a vaccuum, so they need to have their dependencies filled somehow. Sometimes just providing a value is fine. Sometimes you need to provide a mock in the constructor. Sometimes via IoC containers. Sometimes via private test accessor. It's all injecting some test thing into the class so it can work in isolation.

9

For people who already know about DI, but just have never seen the point, I think unit testing will almost invariably lead to using DI.

If you don't know about DI and are trying to write unit tests, some people will naturally reinvent DI, some will get frustrated and eventually discover DI through research, but you'd be surprised how often it simply won't occur to someone that there might be a better way to architect their software to make unit testing easier. Those people write off unit testing as intractable and give up.

8

Unit testing will lead to DI (since it forces you to create loosely coupled units). TDD not necessarily, since TDD can also be used for creating tests layer-by-layer, instead of "verbatim" unit tests. See this article

http://stephenwalther.com/archive/2009/04/11/tdd-tests-are-not-unit-tests.aspx

for an explanation of the differences.

5
  • 1
    +1 for "TDD is not UT". Also for recognizing that the extreme uncoupling is a common result of UT, not (necessarily) of TDD.
    – Javier
    Aug 15, 2012 at 22:41
  • *A Unit is not a Class Aug 30, 2022 at 7:05
  • @MichielDeRouter: if you like to contribute, please tell us clearly what you mean.
    – Doc Brown
    Sep 1, 2022 at 2:05
  • @DocBrown I don't agree with the article. TDD as described by Kent Beck in his book does not define a Unit to be a class. Therefore there is no need to differentiate between a TDD test and a UnitTest. They can be exactly the same thing. There is no value in a Unittest if it tests HOW the result is being achieved (calling certain methods in a certain order for example). It only makes refactoring harder. I've written tests that considered a Unit to be the whole application or just one method, testing only the input and output or in other words, the value that it delivers. Sep 14, 2022 at 14:00
  • @MichielDeRouter: the term "unit testing", for most people here, means testing of small, isolated units, which may be larger than just one class, but normally a lot smaller than a full-blown application. I am pretty sure Kent Beck would agree to this characterization. However, as you wrote by yourself, TDD can be used in conjunction with larger tests which span multiple layers in an application and would IMHO not deserve the name "unit test" any more. That's what I wrote, and that's also described in that article. Neither me nor that article said a unit must be class.
    – Doc Brown
    Sep 14, 2022 at 15:22
3

Yes and no: TDD leads to writing well-structured code, which itself leads to DI.

By that I mean TDD generally sends you the right way with regards to encapsulation, SRP and reusability. It's not just about getting some tests round your code: it's about using those tests to flesh out a better design. If an object creates its own dependencies, then it's living within a specific context within a specific application and is likely to be woven into the application to a greater degree. DI is a good thing, not just from a testing point of view, but also from a code quality point of view.

2
  • Could you clarify the no part of your yes and no answer? How does one do TDD without DI.
    – Gilles
    Aug 15, 2012 at 16:13
  • The 'no' part being I don't think it's a direct link between TDD and DI. It's indirect via code quality. Which is splitting hairs probably, but just thought I'd point out that code quality is the thing you're aiming for, not just testability.
    – Tim
    Aug 15, 2012 at 16:15
0

As already pointed out in other answers, TDD does not require unit tests. You can just as well write integration/functional tests while doing TDD. Of the several ways to apply TDD, creation of unit tests would be the "fake it till you make it" way (see the book by Kent Beck for details).

As for "TDD inevitably leads to DI", it definitely does not. What one needs when writing unit tests is to isolate the unit being tested from the implementations of its external dependencies. And this can be done just as easily with or without DI. The best way, probably, is to use a proper isolation/mocking tool.

1
  • 2
    But to use mocks mustn't you necessarily inject the dependencies in the class?
    – Gilles
    Feb 1, 2014 at 1:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.