๐จ๐ป๐ถ๐ ๐ง๐ฒ๐๐๐ถ๐ป๐ด ๐ฆ๐ฐ๐ต๐ผ๐ผ๐น๐ ๐ผ๐ณ ๐ง๐ต๐ผ๐๐ด๐ต๐
A unit test is an automated test that verifies a small piece of code quickly and in isolation.
Controversial attributes within this definition are the unit and isolation attributes, controversies are due to these terms being defined differently by unit testing schools.
Two unit testing schools are known as the Classical (aka Detroit) school, the teachings of this school are prevalent in the book โTest-Driven Development: By Exampleโ by Kent Beck. The other school is the London (aka Mockist), teachings of this school are found in the book โGrowing Object Oriented Softwareโ by Steve Freeman.
๐ง๐ต๐ฒ ๐๐ผ๐ป๐ฑ๐ผ๐ป ๐๐ฐ๐ต๐ผ๐ผ๐น is based on mocking most collaborators of the system under test, therefore isolation manifests here in the form of isolating the system under test from its collaborators, while a unit is usually identified as a single class; this approach yields several advantages:
๐ญ. Easy identification of areas of failure: The substitution of collaborators with test doubles eliminates them as causes of failure allowing developers to focus on the unit under test to rectify failing tests.
๐ฎ. Convention: As a unit is a single class, it becomes easier to organize and locate test code by creating a corresponding test class for each production class.
๐ฏ. Reduces object-graph complexities: As dependencies are replaced with fakes, we need not concern ourselves with the sub-dependencies of the SUTโs immediate dependencies.
๐ง๐ต๐ฒ ๐๐น๐ฎ๐๐๐ถ๐ฐ๐ฎ๐น ๐๐ฐ๐ต๐ผ๐ผ๐น teachings specify that tests should revolve around units of behavior, a unit of behavior may be achieved by anything from a single method to a set of classes collaborating together, while isolation is focused around isolating tests from each other by allowing them to run independently from each other and in parallel. This approach presents a number of benefits:
๐ญ. Better resilience to refactoring: The classical school keeps the use of mocking to a minimum and encourages the use of real/production collaborators instead, this means that tests are decoupled from implementation details, you no longer have to verify every method call this way if a method changes within a unit of behavior the test will still pass.
๐ฎ. Easily understood tests: Granularity can make it difficult to understand the bigger picture, therefore focusing on behavior leads to better-understood tests โ๐ ๐ต๐ฆ๐ด๐ต ๐ด๐ฉ๐ฐ๐ถ๐ญ๐ฅ ๐ต๐ฆ๐ญ๐ญ ๐ข ๐ด๐ต๐ฐ๐ณ๐บ ๐ข๐ฃ๐ฐ๐ถ๐ต ๐ต๐ฉ๐ฆ ๐ฑ๐ณ๐ฐ๐ฃ๐ญ๐ฆ๐ฎ ๐บ๐ฐ๐ถ๐ณ ๐ค๐ฐ๐ฅ๐ฆ ๐ฉ๐ฆ๐ญ๐ฑ๐ด ๐ต๐ฐ ๐ด๐ฐ๐ญ๐ท๐ฆ, ๐ข๐ฏ๐ฅ ๐ต๐ฉ๐ช๐ด ๐ด๐ต๐ฐ๐ณ๐บ ๐ด๐ฉ๐ฐ๐ถ๐ญ๐ฅ ๐ฃ๐ฆ ๐ค๐ฐ๐ฉ๐ฆ๐ด๐ช๐ท๐ฆ ๐ข๐ฏ๐ฅ ๐ฎ๐ฆ๐ข๐ฏ๐ช๐ฏ๐จ๐ง๐ถ๐ญ ๐ต๐ฐ ๐ข ๐ฏ๐ฐ๐ฏ-๐ฑ๐ณ๐ฐ๐จ๐ณ๐ข๐ฎ๐ฎ๐ฆ๐ณโ - Vladimir Khorikov
The differences between these schools spills into TDD approaches, allowing either an outside-in approach or an inside-out approach. The liberal use of mocking within the London school means that you donโt have to worry about whether the collaborator's functionality has been defined or not as it is substituted with a fake. In contrast, the Classic school's reliance on real collaborators means that your tests cannot pass until those collaborators have implementations.
Vladimir Khorikov dives into the differences between these schools in his book titled โUnit Testingโ.