DEV Community

Cover image for Prefer Integration Tests? Think twice
Anton Korzunov
Anton Korzunov

Posted on • Edited on

Prefer Integration Tests? Think twice

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.

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

Let's jump!

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:

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?

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??

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 😅.

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.

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.

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.

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.

Integationraptor meme explained?

Top comments (5)

Collapse
 
juancarlospaco profile image
Juan Carlos

Learn Design by Contract. TDD is poormans DbC.

Collapse
 
thekashey profile image
Anton Korzunov

😎 There is no Dev Article about 😎
If you reckon more people should be about DbC - please share your thoughts on the subject!

(reading wikipedia article right now, and I would not say it's quite useful)

Collapse
 
thekashey profile image
Anton Korzunov
Collapse
 
juancarlospaco profile image
Juan Carlos
Collapse
 
mrvaa5eiym profile image
mrVAa5eiym

"Changing code should always break tests" ehm maybe not?