There is often a philosophical debate about whether to write a unit test or an end-to-end test. This has been a common question I have encountered many times – when limited in time and resources, what kind of testing should be done? Weighing up such factors can be difficult, especially given that usually only one type can be conducted.
Let’s start with why:
Why do we Test?
Testing is an essential part of software development. The primary goal is to instill confidence that our code functions correctly. By detecting bugs before they impact users, tests act as a protective layer, ensuring software reliability.
When a feature malfunctions, tests act as detectives, swiftly identifying the root cause. The more precise and granular our tests are in pinpointing issues, the faster we can resolve them. However, when limited in time and resources, choosing between unit tests and end-to-end (E2E) tests can be a difficult decision.
Unit Tests: The First Line of Defense
They are your first line of defence against bugs. A unit test typically has no dependencies, can be executed in milliseconds, and is perfectly reliable and if those units work as expected, It focuses on individual units of work instead of whole applications. The unit of work can be single:
-
function or method,
-
class,
-
module.
Why Are Unit Tests Important?
Whether it be a function, a class, or anything else, unit tests are meant to test every feature/potential logical path. When writing unit tests, it is essential to cover every feature and potential logical path of the code, regardless of whether it is a function, a class, or any other component. Achieving 100% code coverage for the unit tests means that every possible flow within the function, class, or module has been thoroughly tested.
However, in reality, achieving 100% code coverage can be quite challenging and may not always be feasible. Realistically, a good target for code coverage is around 80%. This means that approximately 80% of the code is tested, taking into account different scenarios and logical paths.
End-to-End (E2E) Tests: The Confidence Booster
An end-to-end test is a test that exercises an aspect of the system within the context of the system as a whole. This test not only verifies that the feature works, but also verifies that it works under typical operational conditions.
The end-to-end test is essential, for example, If I want to know that the system I’m delivering meets the requirements and will continue to meet the requirements as the system evolves in the future, It allows me the opportunity to study the application under conditions where these bugs arise and is invaluable for building robust and reliable software systems.
Why Are End-to-End Tests Important?
E2E tests are complex and difficult to implement. They are most common in production-grade code, so you can probably spare yourself the time on pet projects or schoolwork if manual testing is more efficient. In summary, use E2E tests when:
-
There will be users aside from yourself
-
You have enough infrastructure for a staging or dev environment
How Much End-to-End Testing is Necessary?
When it comes to the issue of how much end-to-end testing to perform, the go-to is often the Test Automation Pyramid. This model shows that a majority of automated tests should be unit tests. These are tiny but fast tests that are executed lower than the user interface layer. Then, there are API/integration tests in between, verifying a combination of elements such as data services, APIs and external services. Finally on top is E2E testing which is generally done through UI control. Thus, this pyramid displays how these kinds of tests should be performed for them to be most effective.
To determine the right balance of testing, we refer to the Test Automation Pyramid, which consists of:
Unit Tests (70%) – Small, fast, and focused tests for individual functions or modules.
Integration Tests (20%) – Validate interactions between different components.
End-to-End Tests (10%) – High-level tests ensuring the entire system works correctly.
This 70/20/10 ratio (proposed by Google’s Mike Wacker) ensures an efficient testing strategy without excessive execution time or infrastructure requirements.
Which One Should You Prioritize?
If time and resources are limited, consider the following:
-
Prioritize unit tests for core logic and essential functionality.
-
Use E2E tests selectively for critical workflows and user interactions.
-
Balance with integration tests to verify data flow and service communication.
Conclusion
I don’t think that anyone can argue that testing software is a waste of time. The biggest challenge is knowing what to test and how to test it in a way that gives true confidence rather than the false confidence of testing implementation details.
Whenever possible, I try to write more E2E tests and view unit tests as complimentary to E2E tests. As you move up the pyramid, the confidence quotient of each form of testing increases. So while E2E tests may be slower and more expensive than unit tests, they bring you much more confidence that your application is working as intended.
Overall, it ultimately comes down to whether its purpose/common use cases suit you, and whether their properties (i.e. execution time, required technical infrastructure, etc) are viable for your system.
FAQ’s
1. What is the main difference between unit tests and E2E tests?
Unit tests focus on testing individual functions or components in isolation, while E2E tests validate the entire system’s functionality by simulating real user interactions.
2. Are unit tests necessary if I already have E2E tests?
Yes. Unit tests catch issues at an early stage and provide quick feedback, making debugging easier. E2E tests are broader but slower and more resource-intensive.
3. How much unit and E2E testing should I do?
A good rule of thumb is the 70/20/10 ratio: 70% unit tests, 20% integration tests, and 10% E2E tests. This balance ensures both efficiency and confidence.
4. Can I rely solely on manual testing instead of automated tests?
Manual testing is useful for exploratory and UI testing, but automated tests (unit, integration, and E2E) ensure consistency, speed, and reliability across multiple iterations.
5. What tools can I use for unit and E2E testing?
Popular tools for unit testing include Jest, Mocha, and JUnit, while E2E testing can be performed with Cypress, Playwright, or Selenium.
Leave a Reply