Julio Biason
6 years ago
3 changed files with 71 additions and 1 deletions
@ -0,0 +1,69 @@
|
||||
+++ |
||||
title = "Things I Learnt The Hard Way - Unit Tests Are Good, Integration Tests Are Gooder" |
||||
date = 2019-06-19 |
||||
|
||||
[taxonomies] |
||||
tags = ["en-au", "book", "things i learnt", "unit tests", "integration tests"] |
||||
+++ |
||||
|
||||
The view of the whole is greater than the sum of its parts. And that includes |
||||
tests for the whole compared to tests of single things. |
||||
|
||||
<!-- more --> |
||||
|
||||
First, I just don't want to into a discussion about what's the "unit in a unit |
||||
test"[^1], so let's take the point that a unit test is a test that tests a |
||||
class/function, not the whole system, which would require data flowing through |
||||
several classes/functions. |
||||
|
||||
There are several libraries/frameworks that actually split this in a way that |
||||
you can't test the whole. |
||||
[Spring](https://spring.io/)+[Mockito](https://site.mockito.org/) is one of |
||||
those combinations -- and one that I worked with. Due the bean container of |
||||
Java, the extensive use of Beans by Spring and the way Mockito interacts with |
||||
the container, it's pretty easy to write tests that involve only one class: |
||||
You can ask Mockito to mock every dependency injection in one class and mock |
||||
every injected class, simply using annotations. |
||||
|
||||
And this is cool and all. But the fact that we are making sure each class does |
||||
what it does, it doesn't give a proper view of the whole; you can't see if |
||||
that collection of perfectly tested classes actually solve the problem the |
||||
system is responsible for solving. |
||||
|
||||
Once, in C++, I wrote an alarm system |
||||
[daemon](https://en.wikipedia.org/wiki/Daemon_(computing)) for switches. There |
||||
were three different levels of things the alarm system should do: It could |
||||
only log the message of the incoming error, it could log the error and send a |
||||
SNMP message, or it could log the error, send a SNMP message and turn a LED in |
||||
the front panel on. Because each piece had a well defined functionality, we |
||||
broke the system in three different parts: One for the log, one for the SNMP |
||||
and one for the LED. All tested, all pretty. But I still had a nagging |
||||
feeling that something was missing. That's when I wrote a test that would |
||||
bring the daemon up, send some alarms and see the results. |
||||
|
||||
And, although each module was well tested, we still got one things we were |
||||
doing it wrong. If we never wrote an integration test, we would never catch |
||||
that. |
||||
|
||||
Not only that, but because we wrote a test that interacted with the daemon, we |
||||
could get a better picture of its functionality and the test actually _made |
||||
sense_ -- as in, if you read the unit tests, they seemed disconnected from |
||||
what the daemon was expected to do, but the integration tests actually read |
||||
like "Here, let me show that we actually did what you asked". And yes, this |
||||
was akin to [Gherkin](/books/things-i-learnt/gherkin) tests, although I didn't |
||||
know Gherkin at the time. |
||||
|
||||
Personally, I think over time integration tests are more important that unit |
||||
tests. The reason is that I still have the feeling that unit tests check if |
||||
the classes/functions have _adherence_ to the underlying _design_ -- Does your |
||||
view can actually work without the controller? Is the controller using |
||||
something from the model or using things that should be in the view? -- but |
||||
adherence to the design gets better over time -- developers start using the |
||||
layout from previous examples, so they capture the design by osmosis, while |
||||
the big picture starts to get more and more complex, with lots of moving |
||||
parts. |
||||
|
||||
{{ chapters(prev_chapter_link="/books/things-i-learnt/gherkin", prev_chapter_title="Gherkin Is Your Friend to Understand Expectations") }} |
||||
|
||||
[^1]: There is no "unit" in "unit tests". "Unit test" means the test _is_ a |
||||
unit, indivisible and dependent only on itself. |
Loading…
Reference in new issue