Testing best practices

Jero
5 min readJun 23, 2019

Well, this title it’s a Twitter actually from Guillermo Rauch, and these notes come from the talk from Kent C. Dodds.

Testing is all about achieve confidence.

How much code coverage do you need?

“It depends”

So describe in this talk, Aeron Abramov talks about looking for a Sweet Spot.

So, for example, if you are working on a financial application, you probably want to be more on the right side of the blue line. Because each bug it’s really expensive. Also if you are working in an open-source library, very small and public for a lot of people, also you should fully test your code as well.

If you are working on a regular application, you would like to be in somewhere in the middle of the blue line. And if you are doing an internal tool, maybe you don’t need to do testing at all.

Rules of good tests

  • The tests should run fast (it takes too long, they lose focus, and developers don’t will keep running/using them all the time)
  • The tests should not break often (avoid testing implementation details, false negative)
  • Easy to read and Understand (easy to change)
  • Catch bugs (should avoid false positives)
  • Good coverage to effort ratio (ideally we should create tests that covers several parts of your application)
  • Mocking Too much reduces test quality (because you have two maintain two implementations, the real one and the mocking, and also gets you far away from reality.
  • More isolation for UT will catch errors.
  • Because testing UI is hard, you could decouple your UI test from your business logic test.

Generally, when you start a new project you write bad tests, until you figure out, how to test properly for your project, and choose the right strategy.

Takes time until you get a good test for your project.

So, if we don’t get a good strategy, and all the rest of the team follows the good strategy, we will end up, with some of our suit tests will be good, and others will be bad.

So, once you have a good test, you should share it with the team in order get benefit all of the team.

Keep test clean tips

  • Shared test utilities, do your own DSL for your test to help you to write more clear and descriptive unit tests, implement ESlint, create your mock functions, and put in a commonplace of your project (MSW does a great job for that).
  • Generation of test template.
  • Lint rules
  • Documentation, write documentation about how to deal with good best practices test.

Some ideas about how to separate your test

  • UI components, test the states of your UI component like a state machine, given that props, should render in this way, etc.
  • Data mutations (Separate your mutations that contain side-effects and others without any side-effect at all) test, rate to keep your business logic as pure function as possible, separate your side-effects, and named extremely clearly what it does. Don’t mix between side effects (some Rest calls, DB calls, with your business logic, keep separate and test separately) and pure functions.
  • App routes tests, in your integration test, you could test how to change your app routes.

Avoid implementation details

Implementation details are things which users of your code will not typically use, see, or even know about.

Something that achieves 100% of coverage force to us to test “Implementation detail”. So what does it means?

  1. Can break when you refactor your application code. False Negative.
  2. May not fail when you break the application code. False Positive.

Kent explains for that reason, he stops using Enzyme, also completely avoid shallow rendering, and never use APIs like instance(), state() , or find('ComponentName') .

When you will find a situation where you need to expose private functions, probably you are testing implementation details.

Also, if your test breaks every time that we refactor our component (without changing the actual behavior), the test fails because of are testing implementation detail.

Basically, explain, you should have only two kinds of actors that our test should cover, not three.

  • End-User: The real consumer of our component in real life, which will interact with our rendered/mounted component. Basically will observe and interact with the buttons, contents, etc.
  • Developer user: The developer that is creating the test for the component using props, to give data into the component.

As a result:

  • So our test should typically only see/interact with the props that are passed, and the rendered output.

The Test: that actor we should try to avoid them, it’s a complete waste of time. “ I don’t want tests that are written for their own sake.”

Static code Analysis

  • It’s about format testing like ESLint helps a lot about this.
  • Flow and Typescript are to eliminate this category of test.
  • Semicolons and style stuff should be used for that prettier.

Integration test

  • Should never make an actual network call. You should mock the server response by mocking modules responsible for making the network's calls.
  • It’s really good to make an integration test because of testing a set of functionalities of our app.

This diagram above, shows how “Static test” it’s cheaper, and then unit test, integration test, and an E2E are more expensive (despite the fact that cypress does a really good job, it tends to be more expensive doing e2e testing than a unit test).

Also, startup a full environment like doing E2E, it’s slower than running Unit testing.

So, as much you cover your testing Trophy, so doing from the bottom to the top, much of “confidence coefficient” also goes up.

If you looking for a balance, we could see how Integration testing it’s the balance between cheaper and expensive, and get immediately more confidence too.

It does not say that UT it’s not valuable, he is the point in out, that it’s a good balance and good architecture to focus on integration tests than E2E or unit tests.

Please give me your thought about this short article, I love to share ideas, and learn from others and I hope this article may be helpful to someone out there!

Also, you can be following me on Twitter, or contact me by Linkedin.

--

--