The overall picture of unit testing



This is not a guide to what characters you need to enter in the code editor to get unit tests. This is the food for the mind that needs to be consumed before taking the mentioned actions.

The topic of unit testing is not as simple as it may seem. Many of us, developers, come to unit testing under pressure from customers, employees, colleagues, their idols, and so on. We quickly understand its value, and, having completed the technical preparations, we forget about the big picture, if we ever understood it at all. In this article, I will briefly discuss what unit testing is and is not in general, as well as in PHP, and at the same time I will describe what unit testing takes place in QA.

What is testing?


Before delving into the unit tests, you need to study the theory of testing itself, so as not to make mistakes like the one that the authors of one of the most popular PHP frameworks did: they showed integration tests on their website and called them modular. No, Laravel, these are not unit tests. Although this does not prevent me from still loving this framework.

Software testing is defined as “an investigation conducted to provide information about product quality to interested parties.” This is opposed to "testing software - it is a waste of the project budget by developers who do not do anything important, and then ask for more time and money, because" nothing "can be very expensive." There is nothing new here.

Here is my brief history of becoming a test:


If you belong to the millenial generation, like me, you may be amazed that the teams of testers existed long before you were born. Stop for a minute, inhale, exhale, calm down.
The story shows how over time the type of testing changed, which was considered “good enough” for interested parties. Approximate phases, on what were oriented when testing:


Therefore, unit testing is necessary to prevent inconsistencies between the project and the implementation.

What is testing really?


There are different classifications of software testing. In order to better understand the place of unit testing, I will mention only the most widespread approaches.

Tests are: static and dynamic, "box" (white box, black box, gray box), levels and types. Within each approach, different classification criteria are used.

Static and dynamic testing


Static testing is performed without executing the code. This includes proofreading, checking, code revision (while observing the work of another / pair programming), critical analysis, inspections, and so on.

Dynamic testing to get correct results requires executing code. For example, for unit tests , integration, system, acceptance and other tests. That is, testing is conducted using dynamic data, input and output.

"Box" approach


According to this approach, all software tests are divided into three types of boxes:


Now, in order to confuse you, I will say that unit testing can also refer to the “black box”, since you can understand the module under test, but not the entire system. Although for me it is still a “white box”, and I suggest you agree with this.

Testing levels


Their number varies, usually in the range from 4 to 6, and all of them are useful. Names can also be different, depending on the culture adopted by the company, you may know “integration” tests as “functional”, “system” tests as “automated”, and so on. For simplicity, I will describe 5 levels:

  1. Unit testing
  2. Integration testing.
  3. Testing component interfaces.
  4. System testing
  5. Operational acceptance testing.

Unit testing checks the functionality of a specific piece of code, usually one function at a time. Integration testing tests the interfaces between components so that the modules assembled together form a system that works as intended. This is an important point, because a large number of tests, which are called modular, are actually integration tests, and the developers consider them as modules. If the use of multiple modules is implied, this is testing the integration between them, and not the modules themselves. Testing the interfaces of the components checks the data transmitted between different modules. For example, received data from module 1 - checked - transferred to module 2 - checked. System testing is end-to-end testing to verify compliance with all requirements. Operational acceptance testing is performed to verify readiness for operation. It is not functional, only the serviceability of the services is checked, whether any subsystems damage the environment and other services.

Types of testing


Each type of testing, regardless of its level, can also be divided into other types. There are more than 20 common types. The most common:


From the name it is clear what this or that type of testing is intended for. Bold highlighted unit tests in PHP. If you really want, then each of these terms can be applied to unit testing. However, the main type of unit tests are regression tests, which check whether all modules of the system are executed correctly after making changes to the code.

Now you know that modular tests are dynamic, belong to the “white box” class, are performed at the module level, are regression tests, but at the same time many types of tests can be understood as modular tests. So what exactly are unit tests?

What is unit testing?


V-model is a graphical representation of the above levels, types and their purpose in the software development life cycle.



After checking and approving detailed product requirements, when we started writing code, the unit tests are the first line of defense against any inconsistencies. Therefore, companies that understand what they are doing force developers to use unit tests or even TDD, since it is much cheaper to fix bugs in the initial stages than in later ones.

And this is true. Unit tests have a lot of advantages. They:


However, there are certain limitations that you thought of, probably while reading this list:


The latter is killing me the most. (Almost) in every project, right in the source code of the working application, I find lines like “if this is a unit test, load a surrogate SQLite database, otherwise load another DB”, or “if this is a unit test, do not send an email, otherwise send "and so on. If your application has a bad architecture, do not pretend that you can fix the lousy software with good test passing, it won’t get any better.

I often discussed with colleagues and clients what a good unit test is. Is he:


To those who grinned after reading “automated”: I did not mean integrating PHPUnit or JUnit into CI pipelines. The point is that if you change the code, save it and do not know whether the modules pass their tests, they are not automated, but should. The winning option is file tracking (File watcher).

What should be subjected to unit testing?


In normal systems, unit tests need to be written for:


The definition of a unit test depends on the developer who wrote the code. In PHP, this is almost always a class method or function, because it is an indivisible piece of software that makes sense by itself . Several times I saw how the developers used an array of single-method mini-classes as one module. This makes sense if the minimum functionality requires multiple objects.

So you can determine for yourself what is a module for you. Or you can test the methods one by one, simplifying the life of that guy, who will then work with the code.

If you are not conducting a unit test, I suggest doing this after the next big bug occurs. Check what method it will be associated with, write a failed test with the correct arguments and result, fix the bug, run the unit test again. If it is passed, you can be sure that this bug had to be fixed for the last time (taking into account your specific input scripts).

This approach makes it easier to understand unit testing. Analyze each method separately. Data providers can help determine input and output data for any scenarios that may occur to you, so whatever happens you will know what to expect.

What NOT to test


Slightly more difficult to determine what testing is not necessary. I tried to collect a list of items that do not need to be subjected to unit testing:


I am sure that you should not apply unit testing to any of the above, except for static methods. I like to argue that static, in essence, means procedural, and in many cases, global. If a static method calls another static method, then this dependency cannot be overridden. This means that you are not testing now in isolation. And then this is not modular testing. On the other hand, this is the part of the code that can live on its own, it has a purpose, and it needs to be tested to make sure that whatever part of this confused system the test part of the code causes, it will not break. Therefore, I believe that it is possible to test static methods if you are sure that the output of your test cannot be changed by any other test, and that the language or framework will allow you to test natively.

How to write unit tests?



If “then test it” is not enough, then there are some very good PHP unit testing videos on laracasts.com . There are lots of sites dedicated to the same task in other languages. I see no reason to explain how I perform unit testing, because the tools change quite quickly, and when you read this text, I can switch from PHPUnit to Kahlan. Or not. Who knows.

But answering the first question (how to write code suitable for unit testing) is much easier, and the situation is unlikely to change much over time:


Now, knowing what unit tests are and are not, what is needed and what is not needed to be tested, what place the module tests take in the software development life cycle, it will be easier for you to implement them. It remains to find a framework or library for the soul. If in doubt, take the framework / language that has become the de facto standard.

In conclusion: unit tests are very important both for developers and for business. They need to be written, there are proven techniques that will help you easily cover the modules with tests, mainly by preparing the modules themselves. But all these techniques do not make sense without knowledge of the theory of testing described in this article. You need to be able to distinguish unit tests from other types of tests. And when you have a clear understanding in your head, then it will become much easier for you to write tests.

Source: https://habr.com/ru/post/412695/


All Articles