Do you even unit test, bro ?
Tags: tests, testing, first, unittest
Published: 2019-08-13 21:44:12


<p align="center">
  <img alt="I don't always test my code, but when I do, I do it in production" src="https://thepracticaldev.s3.amazonaws.com/i/opzje4q2t83pwio9c042.png"/>
</p>

# Unit test is rocket science

A lot a coders don't write any unit tests. The main reason if that they don't understand why the should spend time on this. It's just a waste of time, right ?

I was exactly like that, then my code start crashing in production. On big and visible projects. So, I looked for a way to be more confident about my code, about my commits.

Unit test was the first answer, but it took me time before writing them correctly.


## What is a good unit test ?

To write a good, rock solid and trusty unit test, you need to:

* **Understand what you are testing**. That may sound stupid or obvious, but it's not.  Read the method, understand what it does, how and why. How can you test it if you don't know what it should or shouldn't do ?

* **Avoid the "over mocking" syndrom**. Mocking make writing test easy, but it's not a good practice. Only mock if you don't have any other choice, like for an API call. And, please, don't stub the class you are testing !

* **SEAT**. Setup, Exercises, Assert, Teardown. And repeat for each tests.

* **I/O**. Focus on data transformation. Defined a start state, run the test, assert on the output. What happened during the process, or how it happened is not your concern.

* **Decide a scope. Stick to it**.  A method can have as many tests as you want, but try to separates tests in use case scenarios.
You want to assert that a method transform an array to json, but also throw an exception ? Alright, make it 2 independant tests !

## Does code coverage really matter ?

TL;DR: **No. It does not**.

I've heard a LOT of people saying that you should aim for 100% code coverage. But that's a bad idea.
Don't get me wrong, the higher code coverage you have, the better. But it should not be your main concern, neither your objective.

I ask myself a few questions before writting a test for a method:
* Does the method transform the data ?
* Can I write this test without mocking what the method will output ?
* Does the method returns something at all ?
* Can I make an assertion on the result ?

If any of this questions is anwsered by a no, it is likely I'll not write any test.

It's not because you have 100% code coverage that your code is tested properly.

## You shall not pass !

<p align="center">
  <img alt="You shall not pass !" src="
https://media3.giphy.com/media/PShPwoSC3HAR2/giphy.gif"/>
</p>

Code is composed by public methods, yes, but also by private and protected ones.
Should we test them ?

**Of course not. But also yes !**

They usually contains the business logic, so, yeah, test them. But, unlike public methods, the are not worth a specific test.
The purpose of a private method it's to be called by a public method of the same class. Let's apply the same logic inside our tests. Private and protected methods should be test through public method's tests.

## Always be F.I.R.S.T

I am used to write tests following the FIRST principles, but other methods exists, like AAC for example.
I assume that, as a developper, you know how to use Google to find them if FIRST is not a good fit for you !


<p align="center">
  <img alt="Timey wimey dr who" src="https://media1.tenor.com/images/36c1e3ad00040f5e8ef886332613317a/tenor.gif?itemid=7863239"/>
</p>

- **Fast**: A test should be light fast. If not, I'll discouraged you or your team from running it. Big project may have thousands of tests and assertations.
Setup, test and tears down should not take more than a few milliseconds

* **Independent**: Tests **must not** depends on each other, or on the state of a previous test.
All data needed should be created for the current test, and destroy afterward. 
If you need the same data for many tests, just create it during setup.

* **Repeatable**: Tests should be repeatable over and over. Time, date or zone should not affect them.
Yes. You can be a Time Lord and mock Time (unless it's a fix point in time, of course ;-) )
Remember, if a test failed, the only valid reason should be that the method is not working as expected. Or that the test is wrong. But that's all folks !

* **Self-validating**: No manual inspection required to check whether the test has passed or failed.

* **Thorough**:  Don't be lazy. Unit testing should take time to write, sometime even more than writing the method itself.
	* Test every use case scenario
	* Don't limitate yourself for simple values. Go for edge values
	* If the methods can process bulk data, test if with a large data set
	* Tests for exceptions and errors
	* Don't only test for success. You can assert a faillure, and you should !

## Conclusion
Keep your tests simple, limit them to a specific scope and focus on the output of the method.

Unit test is just the first step for a complete test cycle. Take a look on the pyramid bellow.

<p align="center">
  <img alt="Idea test pyramid" src="
http://www.testingreferences.com/pyramids/Bagmar2012.jpg"/>
</p>