Most people can't write unit tests. And even those who apply unit tests in daily development often recognize that the resulting tests are sometimes not very effective for certain reasons. I can attribute myself to this category of people. First of all, this “cause” is some emerging “inertness” of the code, which consists in the fact that if you need to change some key algorithm a little, add a couple of lines of code, then ~ 100 unit tests will “fall” and you have to spend a long time time to make them work again. So, let's proceed to the "good recommendations" when writing automatic unit tests. No, I will not be the captain of evidence, once again describing the popular style of writing tests called AAA (Arange-Act-Assert). But I will try to explain how Mock differs from Stub, and that not all test objects are “mocks”.
Globally, unit tests can be divided into two groups:
state based tests and
interaction tests .
State Tests — Tests that verify that the object's called method worked correctly by checking the state of the object being tested after calling the method.
Interaction tests are tests in which the test object performs manipulations with other objects. They are used when you need to make sure that the test object interacts correctly with other objects.
')
It is also worth noting that a unit test can easily turn into an integration test if testing uses a real environment (external dependencies) - such as a database, file system, etc.
Integration tests are tests that check the performance of two or more modules of the system, but
in aggregate - that is, several objects as a single unit.
In interaction tests, a specific, specific object is tested, and how it interacts with external dependencies.
External dependency is an object with which the code interacts and over which there is no direct control. To eliminate external dependencies in unit tests, test objects are used, for example, such as stubs (stubs).
It is worth noting that there is a classic work on unit tests for the authorship of Gerard Mesarosh called "
xUnit test patterns: refactoring test code ", in which the author introduces as many as 5 types of test objects that can easily confuse an unprepared person:
- dummy object , which is usually passed to the class under test as a parameter, but has no behavior, nothing happens to it, no methods are called. Examples of such dummy objects are new object (), null, “Ignored String”, etc.
- test stub (stub), used to retrieve data from an external dependency, replacing it. At the same time, it ignores all data that can come from the test object to the stub. One of the most popular types of test objects. Does the test object use reading from the configuration file? We pass it the ConfigFileStub that returns the test configuration lines to get rid of the dependency on the file system.
- test spy (test spy), used for interaction tests, the main function is to record data and calls coming from the test object for subsequent verification of the correctness of the call to the dependent object. Allows you to check the logic of our test object, without checking the dependent objects.
- mock object (mock object) is very similar to a test spy, however it does not record a sequence of calls with the parameters passed for subsequent verification, but it can throw exceptions when incorrectly transmitted data. Those. It is the mock object that checks the correctness of the behavior of the object being tested.
- fake object (fake object), used mainly to run (un-run) tests (faster) and speed up their work. A kind of replacement of a heavy external dependent object with its lightweight implementation. The main examples are an emulator for a specific database application in memory (fake database) or a fake web service.
Roy Osherove in the book "
The Art of Unit Testing " offers to simplify this classification and leaves only three types of test objects - Fakes, Stubs and Mocks. And Fake can be either a stub or a mock, and the test spy becomes a mock. Although I personally do not really like the mixing of the test spy and the mock object.
Confused? Maybe. This article had the task to show that writing the right unit tests is a rather difficult task, and that not all of the mock that is created in through the mock-frameworks.
I hope I managed to lead the reader to the basic idea - the writing of high-quality unit tests is quite difficult. Unit tests follow the same rules as the main application they are testing. When writing unit tests, modules should be tested as isolated from each other as possible, and the various types of test objects used in this certainly help. The style of writing unit tests should be the same as if you wrote the application itself - without copy-paste, with thoughtful classes, behavior, logic.