100% test coverage is not enough...
Tags: javascript, react, testing, architecture
Published: 2019-12-05 14:54:51

<b>Even if your unit tests cover everything and pass at build time, your app can still be completely broken in production.</b> 🧐🤔

In web application development, testing is crucial. 
You can't build a high-quality app without proper testing.

So today we will talk about *TESTING*. Hello, Mic, Testing 1,2,3,4 … 🎤

<img src="https://media.giphy.com/media/f9SgNsok0zsxI3vS56/giphy.gif" />

We test in one of two ways:

- Manual

- Automated

<h4>Manual Testing</H4>
As the name suggests, the testing is done manually in this case, by humans.
And we can't deny it, we all do it. But that's not what we'll talk about today.

We will talk about Automated Testing 🤖

<h4>Automated Testing</h4>

There are three different methods of Automated Testing:

- Unit

- Integration

- End-to-End

Let's take a closer look at each approach.

<h5>Unit Testing</h5>

- Unit tests take a piece of the product and test that piece in isolation.

- Unit testing should focus on testing *small* units.

- Units should be tested independently of other units. 
This is typically achieved by mocking the dependencies.

<h5>Integration Testing</h5>

- Integration testing is when we integrate two or more units.

- An integration test checks their behavior as a whole, to verify that they work together coherently.

<h5>End-to-End Testing</h5>

- End-to-end testing is a technique used to test whether the entire application flow behaves as expected from start to finish.

- Tests that simulate real user scenarios can easily help to determine how a failing test would impact the user.

Wow, now we know a bit about what those three mean :clap:

<b>Now let's dig into Unit Testing and the associated tools.</b>

In the last few years, several tools have been popular, including:

- [Karma](https://karma-runner.github.io/4.0/)

- [Mocha](https://mochajs.org/)

- [Jest](https://jestjs.io/)(*which is what we'll talk about here*)

<b>What is Jest?</b> (From its official site)

Jest is a delightful JavaScript Testing Framework with a focus on simplicity.
It works with projects using: Babel, TypeScript, Node, React, Angular, Vue and more!

For this article, we use [React](https://reactjs.org/) examples, but the approach would be similar in other frameworks.

First, let's see how Jest works. We have a module called `sum.js` -

```javascript
function sum(a, b) {
  return a + b;
}
module.exports = sum;
```

We can test this using Jest in `sum.test.js` like this:

```javascript
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
```

And wow, it will pass. :clap: awesome!!!

But what happens, if we use `null` or `"1"` -
```javascript
sum(null, 2);
sum("1", 2);
// etc...
```

You might try to add all the possible cases to test it and make it solid. But let's be honest - most companies don't research all the test cases for any unit.

But for the sake of simplicity, let's assume this function is tested enough to work perfectly. So, we need to find out all the units of the app and test them  in the same manner.

And then again, do we really know what the Units of the app are?

*For example*:

We don't know the value of `a` and `b` for the `sum` function. They come from 2 separate modules.

```javascript
function getA() {
  // calculations or Remote API call
  return a;
}
module.exports = getA;
```

```javascript
function getB() {
  // calculations or Remote API call
  return b;
}
module.exports = getB;
```

So, to do the sum operation, we need to do something like this:

```javascript
const a = getA();
const b = getB();
// then the sum op
sum(a, b);
```

But we are really motivated developers and want to prepare unit test for `getA` and `getB` as well as `sum`, so we think we have 100% Unit test coverage.

All our tests pass separately as units - but when we run the whole thing together in production, it still doesn't work as expected.

Then we think of  creating a function named `doEverythingAndReturnSum` which (as the name suggests) does *everything* and returns `sum`:

```javascript
function doEverythingAndReturnSum() {
  const a = getA();
  const b = getB();
  // then the sum op
  return sum(a, b);
}

```
Wow, nice.
--But hat is the Unit here?

`getA` ? `getB` ? `sum`? or  `doEverythingAndReturnSum` ? 💭

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/e9hzztwir2mc7c70yss8.png)


If we now test all the units separately and feel happy that our app has 100% test coverage, the result might look something like this 🙈💥

<img src="https://media.giphy.com/media/vvLWidwZNYH5e/giphy.gif" />

So far, we've been looking mostly at the JavaScript code, not the user interface. But as we know, UI testing is even more challenging, as there are multiple layers of code involved:

- [DOM](https://en.wikipedia.org/wiki/Document_Object_Model)
- styles
- events
- Data coming from Remote APIs
- Browsers, and so on

When we talk about UI testing for React apps, the first thing that comes to mind is "Components".
Components are the building blocks for a React app. 
- So, of course, we need to test the components.

One of the most popular tools for testing React components is [Enzyme](https://airbnb.io/enzyme/).

<b>Enzyme</b> is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output.

Let's look at an example of how we can unit-test a component with Jest and Enzyme.

We have one component called `MyComponent`, and we pass a `<div>` element to it with a class named `unique`

To test it, we assert that after rendering, the component should include the `<div>` with the `unique` class:

```javascript
import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';

import MyComponent from './MyComponent';

describe('<MyComponent />', () => {
  it('renders children when passed in', () => {
    const wrapper = shallow((
      <MyComponent>
        <div className="unique" />
      </MyComponent>
    ));
    expect(wrapper.contains(<div className="unique" />)).to.equal(true);
  });
});
```

Fair enough!

It passes, which means it has a `<div>` element and the `unique` class.

*But wait...*
--What if in the same Commit, I completely destroyed the styling of the `unique` class? This test will still pass 🤨

There is another way of testing React Components - Jest Snapshot testing. That's also another unit testing mechanism which is not enough on its own. You can read my another post here [Jest Snapshot Testing for React Components is useless? Is it slowly dying? 🧐🤔😐](https://dev.to/destro_mas/jest-snapshot-testing-for-react-components-is-useless-is-it-slowly-dying-4cce)


Also, we may have hundreds of React Components in the project. (If your project is big enough, you could even have thousands). If we unit-test all the components separately,  that doesn't necessarily mean all the components will work together well.

Even if we ignore the remote API for a second, it still doesn't guarantee that.

*Oh, another fun thing:*
--Our application is a web app and it will run in a browser *(and  even in multiple browsers -- as we don't know which browsers people will use)*.

But we aren't testing components in a single browser yet. How can we guarantee that it will work properly in different browsers?

Long, long ago in 2015 (long ago, because in the web or JS world, 2015 is considered ancient times), Google posted an [article on the Testing Pyramid](https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html):

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/grno6c997aj2kjxzg9f8.png)

They suggested to do mostly unit testing and not much end-to-end (E2E) testing: ["Just Say No to More End-to-End Tests"](https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html).

Martin Fowler gave his thoughts on the [TestPyramid](https://martinfowler.com/bliki/TestPyramid.html) even before in 2012:

*Its essential point is that you should have many more low-level [UnitTests](https://martinfowler.com/bliki/UnitTest.html) than high level [BroadStackTests](https://martinfowler.com/bliki/BroadStackTest.html) running through a GUI.*

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ss0e8z5c9pez2cwlbjyh.png)

This thought from Martin seems realistic, so you can actually take your decision based on your financial resources and team strength.

[Kent C. Dodds](https://kentcdodds.com/blog/write-tests) merged these both and came up with this-

 ![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vidbkn85c1axhih6rhq1.png)

Awesome!

Also, he proposed what he calls the "Testing Trophy", which focuses mostly on the integration testing.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/kj9yo6dm4vgpo9zh8x8n.png)

With today's web, I think we cannot rely on unit testing alone. It's better to use a lot of integration testing to make the application solid.

As [Guillermo Rauch](https://rauchg.com/) said -

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/yn4e3eefy1ww9q9ngc2d.png)

The "application" concept on the modern web is changing rapidly. The browser can do a lot more than before. JavaScript is evolving with [ESNext](https://esnext.github.io/esnext/). In fact, time has also changed the testing tools. Nowadays, we have more tools and frameworks to do integration and E2E testing in a much better way.

I plan to show how we can do integration and E2E testing in a better way for modern web applications in future articles.

Till then,
Cheers!
:wave: