From b3521f7b58cebce64b21affa9f02cc97a618ca0c Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Mon, 19 Nov 2018 16:13:34 -0200 Subject: [PATCH] more discussions about unittests --- content/on-unittests-and-layers-2.md | 56 +++++++++++++++++ content/on-unittests-and-layers.md | 92 ++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 content/on-unittests-and-layers-2.md create mode 100644 content/on-unittests-and-layers.md diff --git a/content/on-unittests-and-layers-2.md b/content/on-unittests-and-layers-2.md new file mode 100644 index 0000000..578fdc3 --- /dev/null +++ b/content/on-unittests-and-layers-2.md @@ -0,0 +1,56 @@ ++++ + +title = "On Unit Tests and Layers, Part II" +date = 2017-09-15 + +category = "code" + +[taxonomies] +tags = ["unit tests", "en-au"] ++++ + +After coming with a discussion about unit tests and layers, I got a +bunch of other insights, specially from a video of Gary Bernhardt +about "Fast Test, Slow Test". + + + +Just after posting about +[who one could see the layers through unit testing](./on-unittests-and-layers.md), +I finally watched a video of Gary +Bernhardt (of the "DestroyAllSoftware" fame) about "Fast Test, Slow Test": + +{{ youtube(id="RAxiiRPHS9k") }} + +Basically, what Gary is going after is saying "write tests for the layer ONLY, +so all your tests are fast". Ok, I can get behind it, in a way. Because layers +have their behaviour -- in a "mechanical" sense, since they don't require +human interaction, but behaviour nonetheless -- so you're testing behaviour. + +But that also rises one question: *What are you testing?* Are you testing the +*component* or the *application*? What do you deliver, anyway? *Components* or +an *application*? How do you make sure you're delivering an application in the +proper way? + +Testing layer behaviour also has a bad side effect: If you're application +doesn't need a certain part of your layer -- say, you wrote a validator in the +model layer, but the powers to be decided it wasn't required anymore --, how +do you make sure it will go away? Your tests will still test those validators +-- after all, you're testing your model layer -- and your coverage will still +point that that piece of code is needed and you'll end up with a bunch of dead +code that is kept alive only because the tests require them. + +Also, because Gary points out that the "integration tests" are still required, +you'll end up with a lot more tests than necessary. Why not focus on the +behaviour your *application* should have instead of the behaviour your +*layers* have? + +I'm not against layer testing per-se, I'm just against writing tests that do +not reflect the general expected behaviour of the application and duplicating +tests because you're testing layer after layer and then testing them all +together. You should test the *value* of your application, not its components. + +On a side note, Gary still does the same mistake everyone does, calling the +"all layers" tests "system tests". That's wrong. Just because you're going +through different layers it doesn't mean it can't be a unit test. It depends +only on itself? Does it test behaviour? Congratulations, you have a unit test. diff --git a/content/on-unittests-and-layers.md b/content/on-unittests-and-layers.md new file mode 100644 index 0000000..88f9fef --- /dev/null +++ b/content/on-unittests-and-layers.md @@ -0,0 +1,92 @@ ++++ +title = "On Unit Tests and Layers" +date = 2017-09-11 + +category = "code" + +[taxonomies] +tags = ["unit tests", "en-au", "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. + + + +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.