The problem I want to discuss is quite strange to me. Several times I was working on the projects where code coverage was one of the key metrics. Unfortunately a lot of managers without technical background know that “High coverage guarantees stable project without regression bugs”. As a result instead of analyzing the project, code base and opportunities project comes to decision that “Unit Tests will save us all (and money, of course)”.
Let’s try to think, when Unit Tests are actually one of the best approaches and when they are not an option at all.
By definition Unit Tests test the smallest possible chunk of API: one method, one transformation, one operator. And this definition leads us to several major issues (or disadvantages):
- In more or less complex application it’s sometimes very hard to test one method, transformation or operator in isolation. One method calls several other methods, which can call more methods under the hood creating a call tree. At this point of time people recall stubs, mocks, etc. But unfortunately everything is not super cool here. By definition, you can (and should) replace only the behavior of public members, but sometimes most of the behavior hidden inside private members to encapsulate all the logic from the consumers. As a result a lot of tests I saw on the real projects tested not very small chunks of code, but huge classes and methods;
- Second issue is related to testing of API. API in good classes should be small, but again it ruins the ability to easily test the code. The more code you hide from the API to private members the less code you can easily cover with Unit Tests. I’ve heard several times that people are saying that writing testable code leads to better code quality, but I don’t agree. Testable code has poor encapsulation, which means it’s harder to read and understand;
- And the last issue I want to highlight is related to mocking the data and dependencies. My personal opinion here is that each time you mock some parts of your code to test other parts of code you significantly reduce the correctness and coverage of your test scenarios. I mean that when you mock something you only provide state which you expect (correct or incorrect), but in reality it’s quite an often situation when component A is correct in isolation, component B is correct in isolation, but integration between these components is incorrect and you cannot test such cases in Unit Tests;
At this point of reading you probably have a question “when should I use Unit Tests then?”. Let’s think, we should avoid 3 concerns above, it means that you should be able to split code into small independent chunks, code should contain minimal amount of private members, code should have zero dependencies and no side effects. So yes, my opinion is that Unit Tests are very good only when you want to test pure functions, because by definition pure functions have no dependencies, have no side effects, they are relatively small (because it’s very easy to combine them). What it means for Front-end development? It means that you should cover with Unit Tests only service layer of the application (business logic layer). By service layer I mean part of code which is responsible for getting data from back-end services and transforming it into data, suitable for UI. In modern applications this layer is quite thin, because well-designed REST services provide data, which can be easily used on front-end.
But what about regression? In my opinion for front-end UI applications you should concentrate on other approaches:
- For small applications with short development cycle probably the best way to keep it tested is to have a manual QA;
- For large applications with long development you should consider to start writing e2e tests as early as possible, because on the long run e2e tests will significantly reduce time consumed on regression testing by manual QA;
- For applications with high amount of visual data (e.g. charts) you can try to use visual regression testing (screenshot comparison);
Summary. Of course this is only my opinion, but it’s based on my past experience. My experience shows that even on the projects with high Unit Tests coverage the risk of regression is very high. Taking into account the fact that writing Unit Tests consumes a lot developer’s time I would consider this practice is overrated. On the other side I have several projects, where e2e tests kept the project stable enough with relatively small headcount of test automation engineers.