The source content for blog.juliobiason.me
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
4.7 KiB

+++
title = "On Unit Tests and Layers"
date = 2017-09-11
[taxonomies]
tags = ["unit tests", "testing", "layers"]
+++
On a recent discussion about testing, I think I came up with a
reason why some people really think we need to test everything: they
are thinking in layers, without even realizing it.
<!-- more -->
This weekend I had an idea on why some people insist on writing tests for
every single function and object, but first you must know that 3 things
happened:
First, I told someone a programmer-joke like this: "You can't teach top-down
development to newcomers 'cause they don't know which side is up." (Actually, I
heard from someone else; I'm not that smart to come with a line like this).
Yes, it is a joke; yes, it is somewhat fun, but at the same time, it is a
reality: we should let newcomers get wet before telling them how to properly
design their project.
The second is that I got "drafted" to do a tutorial on DjangoRestFramework and,
because I was expecting someone to ask how to manage validation on forms and
serializers and decided to learn a bit more about "fat models", which basically
says you should put all your business rules on the model layer. And here is the
part that stuck with me: the model is not an *object*, but a *layer*.
{% note() %}
"forms" are responsible for validating incoming HTML form content;
"serializers" are responsible for validating incoming data from the API --
although "serializers" are also responsible for serializing the output data
back to the client.
{% end %}
The third is that I was summoned to explain to a group to explain what should
be tested. Thing is, they did a "fizzbuzz" code in which they had
`multiple_of_3`, `multiple_of_5`, `multiple_of_15` and someone mentioned
that we *should* test them too.
And that's what got me thinking: Should we test it? My response for this
question is always "no, think your project is a black box in which you press a
button and some light goes on; you don't need to know if there is a nerve
somewhere in your knee that you hit it and your leg does some kicking or if
the signal is sent all the way to your brain and it sends a response back to
the muscle to make it kick, all you need to know -- and test -- is that when
you hit someone in the knee, they kick and *that's* your requirement and
*that's* what you should test." But what if it is not that simple?
The model *layer* has a responsability and has its own requirements: It should
receive the data and store it somewhere; it can expose some business rules (as
validation of said data) but shouldn't run those rules. The controller *layer*
also has its own responsabilities and its own requireements: it gets the data
from somewhere, do the checks, validate the business rules and then sends it
to the model layer to be store. The view *layer*, again, has its own
responsabilities and its own requirements: exposes the data to the user and
receives data from the user and passes it to the controller layer, exposing
the errors back to the user.
In a way, all those layers could be separate projects: because they have a
defined API, one could replace each layer independently -- I could have a
model layer that stores all that in JSON and then replace it to one that
stores in a Stream Processing Database and the controller and view layers will
never know about. All those layers could be separate *libraries* -- a lost art
of getting code with a single functionality and giving it its own space, with
its own build tools and a well defined interface and which is its used by other
projects as a black box: they know the interface, but they don't know how,
internally, the library does whatever it does.
And, because each library has its own code, it will have its own tests.
And that's what people were seeing: They were seeing, unconciously, "this is
another *layer* in the project, this layer should be tested because it can be
replaced any time". Each `multilple_of` function was an *API* exposed from
the model layer and, thus, should be tested. Even if the design doesn't seem
to be layered and appear all around the code.
Thing is, each layer is nothing by itself: There is no use for exposing
business/validation rules without a controller to send the data; there is no
use for something to validate incoming data and apply business rules if there
is noone sending the data and noone to store it; there is no use for something
responsibile for calling business rules check if there isn't business rules.
All three layers are required to do the word -- and that's probably why I
believe you should test them all as a single unity.
But, in the very end, it seems that going full force into unit tests and what
should be tested can actually help people see they layers of their projects.