Julio Biason
6 years ago
1 changed files with 101 additions and 0 deletions
@ -0,0 +1,101 @@ |
|||||||
|
+++ |
||||||
|
|
||||||
|
title = "Let's Not Call It \"Unit Tests\" Anymore" |
||||||
|
date = 2018-05-09 |
||||||
|
|
||||||
|
category = "thoughts" |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["unit tests", "en-au"] |
||||||
|
|
||||||
|
+++ |
||||||
|
I keep seeing people call tests "integration tests", while they are perfect |
||||||
|
unit tests. So maybe what we call "unit tests" shouldn't be called unit |
||||||
|
tests. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
For example, one thing I always mention is that your tests should reflect your |
||||||
|
requirements for the product and nothing more. And a lot of people think this |
||||||
|
is counter productive. |
||||||
|
|
||||||
|
Another thing is that I keep pointing over and over again that the definition |
||||||
|
of "unit test" is a test that doesn't depend on anything else (like any other |
||||||
|
test); if it starts from an empty plate, creates the whole environment |
||||||
|
required for the functionality to be tested, runs something and checks the |
||||||
|
result, it *is* a unit test. |
||||||
|
|
||||||
|
But here is the kicker: A lot of people will say that if you test your class |
||||||
|
or function, then it is a unit test; if you test the whole thing, like a black |
||||||
|
box, it's an integration test. |
||||||
|
|
||||||
|
Hold on a sec. If I'm testing the whole pipeline of functions and classes, |
||||||
|
believing they build a black box of sorts -- something I have no idea how it's |
||||||
|
built inside or how many functions are called or *how* those functions are |
||||||
|
called and *designed* -- so it is an integration test; but if the test also |
||||||
|
builds the whole environment and doesn't require anything else to check its |
||||||
|
results, it is **also** a unit test. |
||||||
|
|
||||||
|
So far, I hope you're following where I'm going. 'Cause I'm going to take |
||||||
|
another detour -- it's quick, I promise. |
||||||
|
|
||||||
|
Remember the first that I mentioned that I believe that tests should reflect |
||||||
|
the requirements of the product? That's basically "When the user types its |
||||||
|
birth day, we should display their age" and "If the user does not have the |
||||||
|
required license for a product in their account, the action should not be |
||||||
|
displayed". This is usually where people fall back to BDD and write tests in |
||||||
|
Gherkin and such. |
||||||
|
|
||||||
|
And that's the first thing people will complain: If the code is a mess and |
||||||
|
completely messes with all the layers and it's not extensible and such problem |
||||||
|
and such problem *but it follows the requirements*, then it's ok? |
||||||
|
|
||||||
|
And the answer is "yes" -- or, at least, I truly believe it is "yes". |
||||||
|
|
||||||
|
Heck, you're giving value to your users, why isn't that valid? |
||||||
|
|
||||||
|
"It *is* valid, but it shouldn't be just that." |
||||||
|
|
||||||
|
Ok, here is where the two roads join: |
||||||
|
|
||||||
|
If you write a test that checks the product requirement, it doesn't depend on |
||||||
|
anything else and proves that your changes add value to the product... then |
||||||
|
why write tests for the classes and functions and everything else? |
||||||
|
|
||||||
|
No, seriously. There *is* an answer, but you'll let you think a bit about |
||||||
|
this. |
||||||
|
|
||||||
|
Seriously, *why* you're checking a single class when it, alone, provides no |
||||||
|
final value to the product, as it requires coordinated work with other classes |
||||||
|
and functions to actually provide something useful? |
||||||
|
|
||||||
|
The answer for this is kinda hidden in a problem I pointed before: "the code |
||||||
|
is a mess and completely messes with all the layers and it's not extensible and |
||||||
|
such problem and such problem". How do you prevent your code to become a mess, |
||||||
|
to make it still be extensible and not throwing things in the wrong place? |
||||||
|
|
||||||
|
You write *well defined layers* and make sure those boundaries are respected. |
||||||
|
You break things apart to make sure expected *internal behaviors* are |
||||||
|
followed. |
||||||
|
|
||||||
|
You're still not providing product value, but you're checking if your |
||||||
|
perceptions of a good design are being followed. This is why |
||||||
|
you don't test every single function and class, unless every single function |
||||||
|
and class follows your design; you usually don't need to test your `util` |
||||||
|
class/module because it's just something you do to be DRY and that's |
||||||
|
not part of your design. |
||||||
|
|
||||||
|
You may write tests to check if your model/repository layer is doing it's work |
||||||
|
of hiding the implementation of the storage; you may write tests to your |
||||||
|
controller classes/functions to make sure you're trying to add display filters |
||||||
|
on it because that's the view job and you're not trying to go directly into |
||||||
|
the file system to retrieve data because that's the model layer job; and so |
||||||
|
on. |
||||||
|
|
||||||
|
So... It's more like a *developer tests*, isn't it? |
||||||
|
|
||||||
|
I mean, it's not related (at least, not directly related) to the product |
||||||
|
value; it's directly related to the *code* value *developers* perceive in |
||||||
|
their design. |
||||||
|
|
||||||
|
And heck, it should be as much as a unit test like the integration tests are. |
Loading…
Reference in new issue