This article will introduce how to write a unit test. IDE is using Visual Studio Code.

VSCode

First, Open VS Code and install plugins:

  • PHPUnit Snippets
  • PHPUnit Test Explorer
  • PHP IntelliSense
  • PHP Namespace Resolver
  • PHP Debug

Prepare your unit test

First, init composer project

composer init

Input your package name, description, and stability, type, license

Package name (<vendor>/<name>) [adam/adam]: adam/adam
Description []: phpunit test
Author [adam <adam@xxx.xxx>, n to skip]: 
Minimum Stability []: stable
Package Type (e.g. library, project, metapackage, composer-plugin) []: project
License []: proprietary

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]? yes
Search for a package: phpunit
Warning from https://repo.packagist.org: You are using an outdated version of Composer. Composer 2 is now available and you should upgrade. See https://getcomposer.org/2

Found 15 packages matching phpunit

   [0] phpunit/phpunit 
   [1] phpunit/php-timer 
   [2] phpunit/php-text-template 
   [3] phpunit/php-file-iterator 
   [4] phpunit/php-code-coverage 
   [5] phpunit/phpunit-mock-objects Abandoned. Use  instead.
   [6] symfony/phpunit-bridge 
   [7] phpunit/php-token-stream Abandoned. Use  instead.
   [8] jean85/pretty-package-versions 
   [9] brianium/paratest 
  [10] phpunit/php-invoker 
  [11] phpunit/phpunit-selenium 
  [12] johnkary/phpunit-speedtrap 
  [13] codedungeon/phpunit-result-printer 
  [14] spatie/phpunit-watcher 

Enter package # to add, or the complete package name if it is not listed: 0
Enter package # to add, or the complete package name if it is not listed: 0
Enter the version constraint to require (or leave blank to use the latest version): 
Using version ^9.5 for phpunit/phpunit
Search for a package: 

{
    "name": "adam/adam",
    "description": "phpunit test",
    "type": "project",
    "require-dev": {
        "phpunit/phpunit": "^9.5"
    },
    "license": "proprietary",
    "authors": [
        {
            "name": "adam",
            "email": "adam@xxx.xxx"
        }
    ],
    "minimum-stability": "stable",
    "require": {}
}

Test phpunit work

./vendor/bin/phpunit

Init your phpunit configuration:

./vendor/bin/phpunit --generate-configuration

There will three questions and auto-generate:

(Fellowing will using default value)

Bootstrap script (relative to the path shown above; default: vendor/autoload.php):
Tests directory (relative to path shown above; default: tests):
Source directory (relative to path shown above; default: src):
Cache directory (relative to path shown above; default: .phpunit.cache):

Generated phpunit.xml in /php_test.
Make sure to exclude the .phpunit.cache directory from version control.

First unit test

Create tests and src folder, and create a HelloworldTest.php file for unittest demo.

mkdir src tests
code tests/HelloworldTest.php

PHPUnit Snippets plugin will auto generate a quickly notify:

Open HelloworldTest.php, you can type pu: will show lists:

pu:TestCase : will generate a default class

<?php

use PHPUnit\Framework\TestCase;

/**
 * HelloworldTest
 * @group group
 */
class HelloworldTest extends TestCase
{
    /** @test */
    public function test_function()
    {
        // Test
    }

}

When using pu:testFunction will auto-generate test function

<?php
    /** @test */
    public function test_function()
    {
        // Test
    }

Here, using assert:same keyword auto-generate an assert code, and try to prepare our expected and actual value and run our first test:


<?php
    /** @test */
    public function test_function()
    {
        // Expected
        $expected = 'hello';

        // Actual
        $results = 'hello';
        $actual = $results;

        // Assert
        $this->assertSame($expected, $actual)
    }

Run following command or using PHPUnit Test Explorer run first unittest:

./vendor/bin/phpunit

Will output unittest results:

PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.11
Configuration: /php_test/phpunit.xml

R                                                                   1 / 1 (100%)

Time: 00:00.009, Memory: 6.00 MB

There was 1 risky test:

1) helloTest::test_function
This test does not have a @covers annotation but is expected to have one

OK, but incomplete, skipped, or risky tests!
Tests: 1, Assertions: 1, Risky: 1.

Test a Class

That try to create a Hello.php in src, and setting a namespace App.

<?php

namespace App;

class Hello
{
    public function say()
    {
        return "helloworld";
    }
}

Setting composer autoload using psr-4 loading rule:

Here we also setting tests namespace:

{
    "name": "adam/adam",
    "description": "phpunit test",
    "type": "project",
    "require-dev": {
        "phpunit/phpunit": "^9.5"
    },
    "license": "proprietary",
    "authors": [
        {
            "name": "adam",
            "email": "adam@xxx.xxx"
        }
    ],
    "minimum-stability": "stable",
    "require": {},
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}

In test file, we can just add fellowing new Class, and using PHP Namespace Resolver auto-import class:

<?php

namespace Tests;

use App\Hello;
use PHPUnit\Framework\TestCase;

/**
 *helloTest
 * @group group
 */
class helloTest extends TestCase
{
    /** @test */
    public function test_function()
    {
        // expected
        $expected = 'hello';

        // actual
        $results = new Hello();
        $actual = $results;

        // assert
        $this->assertSame($expected, $actual);
    }

}

In this case, we make assert false, and will show the fellowing result:

PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.11
Configuration: /php_test/phpunit.xml

F                                                                   1 / 1 (100%)

Time: 00:00.015, Memory: 6.00 MB

There was 1 failure:

1) Tests\helloTest::test_function
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'hello'
+'helloworld'

/php_test/tests/HelloTest.php:25

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

It says failed asserting that two strings are identical.

We can reset our expected to helloworld, and get the assert true.

<?php

namespace Tests;

use App\Hello;
use PHPUnit\Framework\TestCase;

/**
 *helloTest
 * @group group
 */
class helloTest extends TestCase
{
    /** @test */
    public function test_function()
    {
        // expected
        $expected = 'helloworld';

        // actual
        $results = new Hello();
        $actual = $results->say();

        // assert
        $this->assertSame($expected, $actual);
    }

}