In this paper, starting from https://jaychen.cc/article/34
The author Jaychen
Friend, have you heard of Ann… No, I wrote unit tests.
Unit testing is an essential part of the development process, and a project with good unit testing code will have much more courage to refactor. This time I will write a short article to introduce the use of PHP unit testing tool.
It is not difficult to use PHPUnit. This article mainly serves as an introduction to introduce the basic concepts and usage. With the foundation of this article, you will be more comfortable to read the documents on the official website.
The installation
Installing PHPUnit is simple and can be done in a single line of code using Composer.
composer require --dev phpunit/phpunit
Copy the code
After installation, there is an executable file of phpUnit in the vendor/bin directory. This is the phpUnit ontology. Suppose the directory structure for our project is as follows:
➜ phpUnit tree. ├─ Controller Exercises ── Model Exercises ── service Exercises ──test└ ─ ─ vendor ├ ─ ─ composer. The jsonCopy the code
Where our unit test code is in the Test directory. Use Composer to solve the problem of Autoload for us.
{
"autoload": {
"psr-4": {
"Controller\\": "controller/"."Model\\": "model/"."Service\\": "service/"."Test\\": "test/",}}}Copy the code
If you are not already familiar with the use of automatic composer loading, see this article. Finally, execute Composer Dumpautoload -o to make the automatic loading take effect.
This is the end of our installation. If you are using PhpStorm for development, you need to configure the following:
This indicates where toload PHPUnit. Since we are using Composer to install PHPUnit, select the autoload.php file generated by Composer.
use
Okay, let’s say we’re developing, adding a CalculateService file to the Service directory, and writing a function for ABS.
namespace Service;
class CalculateService
{
public function abs($num)
{
returnabs($num); }}Copy the code
Now let’s unit test the abs function. PHPUnit specifies that a test class must comply with the following rules:
- Unit Test class names must end in Test and must be inherited
\PHPUnit\Framework\TestCase
The base class. - Each test function must begin with test.
The above rules are mandatory and PHPUnit will not treat code as a unit test if it does not. In addition to the above two, there are some good coding habits to consider:
- The unit test code is in the Test directory.
- Each unit test class begins with the name of the class being tested. For example, the class being tested is
CalculateService
, then the unit test class should beCalculateServiceTest
. - Each unit test function should end with the name of the function being tested. For example, the function being tested is
abs
, then the unit test function should betestAbs
.
Write unit test code according to the above specification
class UserServiceTest extends \PHPUnit\Framework\TestCase
{
public function testAbs(a)
{
$userService = new \Service\CalculateService();
$this->assertEquals(4, $userService->abs(4)); }}Copy the code
In the above test code, we call the function abs, and then assert that the result of $userService->abs(4) is 4. In phpStorm, right-click on testAbs and select Run UserServiceTest:
The following output is found in the console
Time: 17 ms, Memory: 4.00MB
OK (1 test, 1 assertion)
Copy the code
$userService->abs(4) == 4 $userService->abs(4) == 4 Note that this does not indicate that the ABS function has passed the test. A good test should include multiple test cases to cover as many possibilities as possible.
Now that PHPUnit’s basic unit tests have been run successfully, there is more information on how to use tests in the PHPUnit documentation. Since there are so many uses of PHPUnit that I can’t explain them all here, here are some others.
-
PHPUnit provides the @test annotation. If a test function is annotated with @test, the test function name does not have to start with test.
-
\PHPUnit\Framework\TestCase has a setUp function. If your own test class overwrites this function, then every time before you start executing the test function, setUp will be performed to initialize the test. There is also a tearDown function that, if overridden, is called after the test function has executed.
-
. Refer to the PHPUnit documentation for more information.
Phpunit. XML file
In the example above, we used PhpStorm to execute the test functions one by one, but if we needed to execute all the unit tests at once, we could write a phpUnit.xml file to do so.
To illustrate the function of phpUnit.xml, give an example of writing phpUnit.xml
<?xml version="1.0" encoding="UTF-8"? >
<phpunit>
<testsuites>
<testsuite>
<directory>test</directory>
</testsuite>
</testsuites>
</phpunit>
Copy the code
test
In addition to using phpUnit.xml to execute all unit tests at once, you can also configure the output logging of unit test results in phpUnit.xml.
<? xml version="1.0" encoding="UTF-8"? > <phpunit> ..... <logging> <log type="testdox-html" target="tmp/log.html"/>
</logging>
</phpunit>
Copy the code
When the phpunit. XML file is executed, a TMP /log.html file is generated in the project directory, which records the results of all the unit tests.
Of course, more information about phpUnit. XML configuration will need to be reviewed in the documentation. :laughing:
The Mock test
PHPUnit also provides Mock tests. Here’s a primer on what a Mock test is.
Assuming that foo calls bar, there are two problems with unit testing foo:
- The foo function depends on the result of the bar function, so the unit test of foo must include bar, so there is no point in unit testing. If the test fails, there is no guarantee that the bug is in foo or bar.
- The bar function may not be executed in the test environment, so foo cannot obtain the execution result of bar and thus cannot be unit tested on Foo.
The Mock test is designed to solve this problem by simulating a call to a bar and assuming that the bar call returns a result. If you still don’t understand me, you should know from the previous code.
class MockTest extends \PHPUnit\Framework\TestCase {
public function testGet(a)
{
$stub = $this->createMock(\App\UserService::class); / / 1
$stub->method('get')->willReturn(3); / / 2
$this->assertEquals(3,$stub->get(1)); / / 3}}Copy the code
The above test function uses the Mock, which is analyzed line by line:
- The first line creates a virtual
UserService
Object. - The second row assumes
UserService
In theget
The return value of this function is 3. - The third line calls
$stub->get(1)
They don’t really executeget
Function, but in terms of the second rowwillReturn
The function simply returns 3.
This is a simple Mock test, but there are many more complex uses of Mock tests, which I can’t expand on here, but it’s not too late to check the documentation for the basic uses and more complex advanced uses when you encounter them in practice.
Ok, so that’s the basic operation of PHPUnit. Unit testing itself is not a difficult thing. It’s not a technical thing that prevents unit testing, but more of a project time measurement and consideration.