Three pillars of Unit Tests
By PAWEL OLESIEJUK in AGILE SOFTWARE DEVELOPMENT, BEST PRACTICES
Ok, now we know what TDD is all about and how to do TDD. Really? Well, no. In fact we only know how TDD works, but TDD is about writing tests (to be more precise – unit tests). What should our tests look like? Here it comes…
What is the Unit?
Why do we call these tests unit tests? The answer is simple – because we test only a unit. Very good answer, but what is this unit? Method, class, module? Unit is simply the smallest part of your system that you can test. If you think about testing something, think about testing only a part of it. If you can imagine that, it means that was not a unit. Now, think about its part. Can you think about testing only part of it… (I think you’ve got my point and if not – read about recursion)
What is the (Unit) Test?
Ok, we have the smallest thing that we can think of. It’s probably
a method, maybe class, doesn’t matter. Think about a simple, but representative scenario of using it. Let’s play with “log in” service. Let the simple scenario be: correct username and wrong password (I’m not saying that this should be the first scenario, but it should be some). The second thing – expected behavior. What should it do under given circumstances? Let’s assume that it should return the message “Wrong password”. And this is our test. Oh, ok, but how do we get the user who exists in database? We have to connect to database, file or something else. This is exactly my point: separations of concerns, isolation. We have to test our “system” in isolation. We don’t want to test our database; we want to test only the “log in” service. So, we have to provide fake data (but about fakes, stubs, mocks and isolation I will write another time) to test only our service’s behavior.
First pillar: Trustworthiness
Unit tests should be our parachute, bungee rope, safety net. Therefore, we have to trust them, otherwise they are useless. If your tests pass, are you confident that it means something? Maybe it is always green no matter what or maybe it doesn’t test what you think it is testing. A common problem appears if you change or only refactor something, run your tests and all are passing but you still aren’t sure if you didn’t break anything. But if you follow red, green, refactor cycle, you can be sure. Firstly, y you saw your tests red (all of them) at the beginning. Secondly, you know they are only passing because you actually wrote a specific code. So, you are confident that if all tests are green your module is fine. You don’t have to check it in another way.
Tip If you have to modify somebody else’s code (let’s assume that there are tests ). First, try something like this. Remove one random line (make it compile, if you have to) or change if/for/while condition and run tests. If they are still passing – it’s bad for you. This parachute is leaky, better don’t use it (or do, but don’t be surprised if you fall down).
Second pillar: Maintainability
It is obvious that tests require care in the same way as production code. If you change production code (refactor, fix bug or add new functionality) some of your tests will breake (it means that neither will they compile nor fail). It is a great issue. The more tests the more attention they need. We can reduce the time we spend on nurturing by writing test only against public method. Public methods are contract.