Today I'd like to write a subtle post about the difference between unit tests, integration tests and acceptance tests. There are tons of articles describing the difference, but I struggled with the topic for some time.
The content of this article was born in discussions with colleagues, sleepless nights and several decaliters of tea (I almost do not drink coffee).
Unit test is the lowest level of abstraction in testing world. It's main purpose is to test the minimal unit of work (hence the name), which is not "related to reality".
The unit of work can be a function, a method or a small class. I think that the main purpose of unit tests is to test SRP on unit's level without external dependencies.
Unit test must be small, fast and independent.
Main features of a unit test:
- All values are held in memory.
- No infrastructure: no threads, no file system, no database...
- All complex external dependencies are mocked
- Checks the behavior of a single unit.
Integration test is a higher level of abstraction than unit test.It is used to test a system (read "a class") in "natural environment", i.e. with real dependencies and environment.
The main purpose is to test the interaction of the components and the integral parts of the system.
For example, one can write a test to check the sequence of module's internal states, which can be reflected in sequential database records.
Do not be mislead by the word "system". A system can be a class that should write a file to the file system :)
Main features of an integration test:
- It uses real environment and infrastructure: threads, database, file system, external dependencies, etc.
- It actually test the interaction of components, not the basic unit's logic.
One more step higher on the abstraction layer.
Acceptance test is used to test the feature of the system in accordance to specification.
It actually test that the system produces the right output using the predetermined input.
But it does not bother on the internal state of the system and it's components. It can be referenced as "black box testing".
Main features of an acceptance test:
- The test is written from the code client's point of view.
- Test checks the key requirements of a specific feature.
- It checks compliance expectations between the spec and reality.
Those three types of tests do not exclude each other. They belongs to different levels of abstraction.
Unit tests and Integration tests can be said to check the system from programmers point of view, and acceptance tests check the system from client's point of view.
Moreover, those test kinds (abstraction layers) can be mixed!
For example, one can write a "unit test" without mocking the database. The main responsibility of this test is to test the behavior of the unit, but as a side effect the test also checks the integration of the behavior with the database (maybe even unintentionally).
Have fun with your tests!