Quality assurance is an important part of web development. In correspondence, a significant part of the QA is testing.
The testing itself is a resource-consuming activity. So it is important to perform it correctly in order to achieve maximum benefit with minimal effort (the definition of efficiency).
Of course, you already heard about unit, integration and end-to-end (E2E) tests. And you have undoubtedly seen this testing pyramid:
The main idea represented by this pyramid is that the majority of test cases must be covered with tests of a lower level, you write a higher-level test only when the test case can not be covered with the lower-level ones.
What does this mean for us in practice? Since, due to the pyramid, unit tests are the most basic ones, they should be written in the first place, and only when we feel we are not able to cover a test case, we proceed with integration tests, right?
What is the problem with this approach?
The thing is that the primary criteria of correctness of work of a web application is its technical requirements. Such requirements are usually written by stakeholders of the application (or under their review).
So when you write E2E tests, you are actually covering test cases defined by the requirements. This means that you are 100% sure that your tests cover a necessary thing.
On the other hand, if you start covering the app from a unit test against, for example, a utility function which calculates the total cost of the cart, how do you even know you are ever going to need this function in your code?
I mean, most probably you will be right in assuming that you will eventually need it. But even if you will, you are guaranteed to fail in predicting the exact API of the function (e.g. number and type of arguments or return value format). And this alone may make all the unit tests against this function completely useless.
In turn, because E2E tests are the highest-level tests, they cover the backbone of a feature (e.g. the entire cart), while leaving you some flexibility for implementation details.
In other words, do whatever you want in the code, just don't break the E2E test.
So now, going back to the cart total cost utility function, I might not cover it with unit tests at all, because it is an implementation detail by itself (which barely worth my attention)! Even if I make a mistake in the function's logic, that's not a big deal, since it is easy to fix. I might even replace the function with a different one (with identical API, of course).
So you have already got my point: write E2E tests first.
Of course, although E2E tests are the most significant tests, they are also the most expensive to write and maintain. That's why it is important to cover with E2E tests only what can't be covered with lower-level tests to avoid over-testing. Otherwise, this will increase cost of the tests themselves and reduce flexibility of the code, which in turn will make further development harder.
So, we have determined the only correct direction of writing automated tests due to the testing pyramid: from top to bottom.
Nevertheless, there is a type of tests that is even on a higher level than E2E tests. Those are manual tests.
Everything tested by an E2E test can be tested by a determined manual test as well. In fact, an E2E test is a derivative of a corresponding manual test. The only reason you are writing E2E tests is that you don't want to perform manual testing on every update (i.e. you want to automate the testing process).
Thus, the testing pyramid might as well look like this:
With manual tests you can cover even more test cases than with E2E tests (in fact, you could cover those cases with E2E tests too, but that would make them unreasonably expensive).
Manual tests have the highest maintenance cost, but the lowest creation cost. You can simply write down test steps on a piece of paper - and you've got a manual test!
This makes manual tests especially useful for some cases like, for example, when you are not sure about your code structure yet, or when the technical requirements are incomplete or are likely to change, or when there is a time pressure and it may make sense to temporarily sacrifice automated testing.
Now, after reading this article you know the only correct way of web application testing: don't start from unit tests, start from E2E or manual tests. Do you agree with this approach? Or have you invented something better? Write in comments!
And of course leave your reaction to this article, share it with friends, and follow me on this platform for future articles!
Don't stop coding, don't stop growing!