Prefer Integration Tests? Think twice
Tags: testing, webdev, codequality, tdd
Published: 2019-07-29 13:07:54

---
title: Prefer Integration Tests? Think twice
cover_image: https://thepracticaldev.s3.amazonaws.com/i/p6vcvrnpqxv4bjc81t6b.JPG
published: true
description: Write tests. Not too many. Mostly integration. But there are nuances.
tags: testing, webdev, codequality, tdd,
series: Do not just code
---
> Philosoraptor meme explained... Just think (twice 😅) about it.

Why I am writing this article? Because twitter might be not the best place to explain the problem, but is the common place to mention it.
What is the problem? Well, the problem is quite well defined at Twitter, as the reply to `Dan Abramov` post.

{% twitter 1151841665335926786 %}

In the following thread, many people tried to agree, disagree, explain and extend this proposal.

Let's jump!

{% twitter 1151986185402605568 %}

Like, 🙀 integration tests are so awesome - you should get rid of all your unit tests right now! They are not giving any confidence at all.
And everybody instantly might think about another tweet:

{% twitter 807626710350839808 %}

- about that famous article, I was asked to read so many times -  [Write tests. Not too many. Mostly integration](https://kentcdodds.com/blog/write-tests) by Kent C. Dodds.

So - why I am writing this article? Because people often don't read articles properly - only clickbait captions. And I asked to think twice. So...

### 1. What was Dan speaking about?

{% twitter 1151842775417151489 %}

I reckon - about "cohesion", the same stuff we like `components` for, among with `CSS-in-JS` and other stuff - _easy to build together, easy to change together, easy to delete together_.

And _cohesion_ between `stuff` and `tests` for that stuff could only be achieved if stuff's tests are "unit", and not testing anything else except their stuff. It's like a definition of the unit testing.

Obviously - if you test your stuff in isolation, that would be just awesome... The only tricky moment - __what is the stuff__.

Like "React" for many of us is just "React", not a combination of smaller files and smaller features. And when someone is testing "React", we expect it as testing "React".

Do you remember the React 15->16 upgrade, when React completely __changed inside__, but not __outside__.

Better think about what React should test... React should test React, to let you code keep working after, and no matter of changes inside React.
That's the only tests you, as a consumer of React, really need.

> 🙀 With today’s release of React 16, we’ve completely rewritten the internals of React while keeping the public API essentially unchanged.🙀 

Hmmmmm...

### 2. What was Kent speaking about?

Well - about the danger of testing things in the isolation. Let me quote the right moment from the original article - _you are testing "umbrella open", and an "umbrella", well, would "open"_. All tests are __green__, all pieces are __working__ ideally!!! What's your __problem__, mate??

{% twitter 1148986961207730176 %} 

That's absolutely true. That's how it should work. If you forgot the main idea of your stuff - to protect someone from the rain, that is The Main, and the only reason for an umbrella to exists. And the rest are implementation details.

Should you use "integration tests" here? Well - it probably would help, as long as there are so many "properly working" umbrellas, which are not 
"properly" protecting you from the rain (I do have one 😓).

### So what then?

First of all - integration tests are not a simple thing. Integration tests are doing two __different__ jobs.

- Firstly - integration tests are checking are you doing the right thing. For example, calling other things in the right order and in the right way.
- Secondly - they are checking that `things` are ok if they are called with provided arguments, and acts as expected. Checks that _things_ are doing what they are expected to do.

So is it a good idea to __prefer integration tests__? What shall you go with unit tests? 

Let me explain it a bit differently.

## A bit differently

I've started coding, well, about 30 years ago. And, to be honest, tests were not something I was doing all this time. Someone even said that _tests were not a thing_ in the "pre agile" era - only manual testing, logging, and monitoring. I am from that Era - the Era when we don't "needed" tests.

> How we were testing stuff before going to prod? Well - we were using the stuff we build, we were consuming the very result. Ate our own dog food.

And it seems to me, what my code was free from any bugs (it is actually still working in production), until I started writing tests. Really - __just after I created my first test - my beautiful code become buggy__.
Coincidence? Not sure 😅.

![](https://thepracticaldev.s3.amazonaws.com/i/gfwjtp019atcldra2exl.jpg)

I've made so many different things - I just had time for it. I've tried so much - I just had time for it. However, I haven't had enought time for tests, and I haven't written many tests - well, due to three reasons.

- reason 1 - everything was working. Test would be just a __waste__ of my time.
- reason 2 - I had no idea what and why to test. So writing tests would __waste__ even more time.
- reason 3 - I wanted to __be free__ to change whatever I wanted, whenever I wanted. So, I didn't want to waste time :) And, of course, I want to be very very __creative__. And tests, as well as TypeScript is limiting your creativity (a town legend)

Sounds familiar? Yeah. So - what then?

- (FYI)I had, and still have some stuff in production, which is not covered by a single test. It's working like a clock for years.
- (🤷‍♂️) I'm doing stupidest mistakes every day.
- (😎) But everything is working.

My experience is telling me one simple thing:
- you need E2E test to understand how "thing" would work for a customer, which would communicate with your app via _human-machine interfaces_ (a mouse). Is your application doing the right thing - that’s the main, everything else is an implementation detail.
- you need Integration tests to understand how "things" are working together (wiring). How molecules and blocks are connected. How some Isolated Domains Behave.
- you need Unit tests to understand how "things" working internally. How your code is really working. Sometimes that’s an easy task, and it’s really hard to make a mistake or code something you was not going to. But sometimes - oh dear 🤦‍♂️.

If you read these 3 propositions more carefully - you will find that they form a pyramid. Not that "testing pyramid", but just a pyramid - every level test one level below it, but not anything else. And all levels are the same.

{% twitter 1160441038411948033 %}

## SO

So - once you secured the right application behaviour by E2E tests - then feel free to do one level down and check how it really works.

> Even a few lines of code, you just wrote, and you are "absolutely confident in" - might work not as you are thinking.

- E2E tests precede integrations - they define the "flow" or your app, and that's the main. Like __what shall be done__.
- integration precedes unit tests as long as they might affect design requirement, and thus architecture decisions for the lower levels. Like __YAGNY__, but for application building blocks. __what we are going to do__.
- unit tests are __how we do it__, and also might precede something else (by induction!), but what?

> Every upper lever precede lower level. level > level + 1

This "testing pyramid" is working well when we are building something from top to the bottom, but it's more often when we are starting building lower-level blocks first, or replacing one low-level block by another - here existing `restrictions` from upper layers would be a _guidance_ for you. If that upper level exists.

> In short - write README before the code. Or specifications.
> But not tests!

You have to have _restrictions_ or _requirements_ beforehand. Not tests!

## Not Tests!

And the idea of this article is quite simple - __there are no such things like integration tests or unit tests__.

There are __tests__, and there are __requirements__. And that's the only difference.
Tests are working for the current layer, and requirements are responsible for the something _next_ to it - they are providing __expectations__ for the next step.

You might change the actual code implementation, and code _requirements_ should still be ok, if they are met.

> 💡 With today’s release of React 16, we’ve completely rewritten the internals of React while keeping the public API essentially unchanged. 🥳

Changing code should always break tests, if something real is changed in real. It's ok to write, rewrite and delete tests - they are disposable.

> So the real question is "do you need tests", or "do you need requirements". While integration/unit separation does not make any sense.

You know - __requirements__ is everything you, and your code, should meet from the business point of view. And from the customer point of view as well.

PS: And TDD(Testing Driven Development) is RDD(Requirement Driven Development) in real - first you shall define "requirements", then "met" them. 

You have to separate these two concepts in your mind - "what" you are testing, not "how" you are testing.

{% twitter 1180497113341468677 %}

Actually "Requirement Based Testing" is a thing, and there is another Dev Article about it -
> Requirements-based testing is a testing approach in which test cases, conditions and data are derived from requirements. It includes functional tests and also non-functional attributes such as performance, reliability or usability.

{% link https://dev.to/vepo/thoughts-on-tdd-tests-and-requirements-e02 %}

Every time you are using `react-testing-library`, which _encourage good testing practices_, and helping you _not to test internals_ - you are doing "requirement based" testing, not just "integration", and it's still important to distinguish top level requirements from lower level requirements, which __are__ implementation details. 

There are more abstract requirements, and more concrete requirements and nuances - together they form the __Real Testing Pyramid__.

As I said - just think twice.


![](https://thepracticaldev.s3.amazonaws.com/i/p6aqu9w55r0rm4q5hh4g.png)

> Integationraptor meme explained?