Search by

pgee70 / ci-phpunit-test

pgee70

An easier way to use PHPUnit with CodeIgniter 3.x

Package info

github.com/pgee70/ci-phpunit-test

Homepage

Forum

pkg:composer/pgee70/ci-phpunit-test

Statistics

Installs: 527

Dependents: 0

Suggesters: 0

Stars: 0

v3.4.2 2026-04-13 05:05 UTC

This package is auto-updated.

Last update: 2026-10-24 01:07:18 UTC


README

This is a fork of kenjis/ci-phpunit-test 3.x, published on Packagist as pgee70/ci-phpunit-test. Upstream's last release targets the original bcit-ci/CodeIgniter 3.1.13, PHP 7.3 - 8.2 and PHP-Parser 4. It doesn't work with the maintained CodeIgniter 3 fork, pocketarc/codeigniter (3.4.x), with PHP 8.4, or with PHP-Parser 5. This fork keeps upstream's API and documentation, and changes only what those three need.

What is different from upstream

pocketarc/codeigniter's bootstrap

pocketarc/codeigniter passes the core classes their dependencies through their constructors. For example, CI_Hooks and CI_URI take the CI_Config object, CI_Utf8 the charset, CI_Security the charset and CI_Input the CI_Security object. They no longer reach for globals.

ci-phpunit-test boots CodeIgniter with its own copy of system/core/CodeIgniter.php (_ci_phpunit_test/replacing/core/CodeIgniter.php), and rebuilds the core objects in reset_instance() (_ci_phpunit_test/functions.php). Both now:

  • load Config first;
  • pass each class the constructor argument pocketarc expects;
  • set CI_VERSION to 3.4.2.

With upstream's files, those classes are built without their arguments, and the bootstrap stops with an ArgumentCountError.

PHP 8.4

  • PHP 8.4 deprecates implicitly nullable parameters (array $x = null). Every such parameter now has an explicit ? type, for example in CIPHPUnitTest::init(), CIPHPUnitTestAutoloader::__construct() and MonkeyPatch::verifyInvoked*(). Without that, every test run prints deprecation notices.
  • composer.json requires php >= 8.4, ext-posix and ext-sodium.

PHP-Parser 5 for Monkey Patching

Monkey Patching parses each included source file with nikic/php-parser and rewrites it: exit(), patched functions, patched methods and patched constants. PHP-Parser 5 dropped the API upstream used (ParserFactory::create() with PREFER_PHP5/PREFER_PHP7, and the Lexer options), so:

  • The patchers create their parser with ParserFactory::createForHostVersion(), so source files are parsed with the grammar of the PHP version running the tests. The method-patch proxy uses createForNewestSupportedVersion().
  • PHP-Parser 5's lexer takes no options and always records token positions, so the Lexer with usedAttributes => [startTokenPos, endTokenPos] is gone.
  • As upstream does, a patched file is regenerated with PrettyPrinter\Standard. Its line numbers therefore differ from the source file, which affects stack traces, Xdebug breakpoints and code coverage of patched files. Turn Monkey Patching off for coverage runs.
  • The php_parser setting of MonkeyPatchManager::init() is ignored now. The sample Bootstrap.php and docs/HowToWriteTests.md still show it, and leaving it in does no harm.
  • Only the PHP-Parser 4.6+ patcher (patcher/4.x) is kept, and it works with PHP-Parser 5. The patchers for PHP-Parser 2.x, 3.x and 4.0 - 4.5 have been removed. So have the copies of PHP-Parser 2.1.1 and 3.1.5 bundled for installs without Composer. PHP-Parser now has to come from Composer (nikic/php-parser ^5.1, a requirement of this package).

Smaller changes

  • CI_Loader::model() in tests: if the CodeIgniter instance already has a property with the model's name, for example because the model is already loaded, it logs a debug message and returns the loader. Upstream threw RuntimeException.
  • CIPHPUnitTestLogger adds getLogs() and didLogsContain($level, $message), which matches part of a message. Upstream's didLog() needs the whole message.
  • reset_instance() stores the Utf8 object in the UNI global and URI in the URI global, as CodeIgniter does.

Not updated

  • .github/workflows/phpunit.yml is upstream's. It runs against kenjis/ci-app-for-ci-phpunit-test on PHP 7.3 - 8.2 and doesn't test this fork.
  • docs/ and _ci_phpunit_test/ChangeLog.md are upstream's. The API they describe still holds; their version and install notes don't.

Warning

Upstream recommends upgrading to CodeIgniter4.

An easier way to use PHPUnit with CodeIgniter 3.x.

  • You don't have to modify CodeIgniter core files at all.
  • You can write controller tests easily.
  • Nothing is untestable, maybe.
  • Well documented.

Screenshot: Running tests on NetBeans 8.1

Requirements

  • PHP 8.4 or later, with the posix and sodium extensions
  • pocketarc/codeigniter 3.4.x
  • nikic/php-parser 5.1 or later, installed by Composer as a dependency
  • PHPUnit 10.5. Upstream supports 9.3 or later; this fork is used with 10.5.

Optional

  • NetBeans
    • Go to Project Properties > Testing > PHPUnit, check Use Custom Test Suite checkbox, and select application/tests/_ci_phpunit_test/TestSuiteProvider.php.

Change Log

Upstream's Change Log goes up to its last release. For the fork's changes, see What is different from upstream and git log.

Folder Structure

codeigniter/
├── application/
│   └── tests/
│        ├── _ci_phpunit_test/ ... don't touch! files ci-phpunit-test uses
│        ├── Bootstrap.php     ... bootstrap file for PHPUnit
│        ├── DbTestCase.php    ... DbTestCase class
│        ├── TestCase.php      ... TestCase class
│        ├── controllers/      ... put your controller tests
│        ├── libraries/        ... put your library tests
│        ├── mocks/
│        │   └── libraries/    ... mock libraries
│        ├── models/           ... put your model tests
│        └── phpunit.xml       ... config file for PHPUnit
└── vendor/

Installation

Install with Composer: Monkey Patching needs PHP-Parser 5 from Composer.

Composer Installation

$ cd /path/to/codeigniter/
$ composer require pgee70/ci-phpunit-test:dev-main --dev

And run install.php:

$ php vendor/pgee70/ci-phpunit-test/install.php --from-composer
  • The above command always overwrites existing files.
  • You must run it at CodeIgniter project root folder.
  • You can specify your application and public folder with option arguments, if you use custom folder paths.
$ php vendor/pgee70/ci-phpunit-test/install.php -a <application_dir> -p <public_dir> -t <unittest_dir>

So the default would be:

$ php vendor/pgee70/ci-phpunit-test/install.php -a application -p public -t application/tests

Upgrading

$ cd /path/to/codeigniter/
$ composer update pgee70/ci-phpunit-test

Read What is different from upstream.

Coming from kenjis/ci-phpunit-test

  1. composer remove kenjis/ci-phpunit-test, then composer require pgee70/ci-phpunit-test:dev-main --dev.
  2. In application/tests/Bootstrap.php, change the vendor/kenjis/ci-phpunit-test path in CI_PHPUNIT_TESTPATH to vendor/pgee70/ci-phpunit-test (see below).
  3. Remove the php_parser setting from MonkeyPatchManager::init(). It is ignored, so this step is optional.

If you want to remove application/test/_ci_phpunit_test/

If you're upgrading from a previous version of ci-phpunit-test that created an application/test/_ci_phpunit_test directory and now want to directly use ci-phpunit-test from Composer, you have a couple of additional steps:

  1. Delete the old test library directory:
    $ rm -rf /path/to/codeigniter/application/tests/_ci_phpunit_test
  2. Edit the application/tests/Bootstrap.php file. At the bottom of the "set the main path constants" section, add the following:
    define('CI_PHPUNIT_TESTPATH', implode(
        DIRECTORY_SEPARATOR,
        [dirname(APPPATH), 'vendor', 'pgee70', 'ci-phpunit-test', 'application', 'tests', '_ci_phpunit_test']
    ).DIRECTORY_SEPARATOR);
    And replace any references to __DIR__ . '/_ci_phpunit_test/ or TESTPATH . '_ci_phpunit_test with CI_PHPUNIT_TESTPATH . '. (So, for example, __DIR__ . '/_ci_phpunit_test/CIPHPUnitTest.php' would become CI_PHPUNIT_TESTPATH . '/CIPHPUnitTest.php'.)

How to Run Tests

You need to install PHPUnit before running tests.

If you use Composer:

$ composer require phpunit/phpunit --dev

Run All Tests

$ cd /path/to/codeigniter/
$ vendor/bin/phpunit -c application/tests/
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 00:00.102, Memory: 12.00 MB

OK (3 tests, 3 assertions)

Generating code coverage report in Clover XML format ... done [00:00.002]

Generating code coverage report in HTML format ... done [00:00.012]

To generate coverage report, Xdebug is needed.

Run a Single Test

If you want to run a single test case file:

$ vendor/bin/phpunit -c application/tests/ application/tests/models/Category_model_test.php

How to Write Tests

As an example, a test case class for Inventory_model would be as follows:

<?php

class Inventory_model_test extends TestCase
{
    public function setUp(): void
    {
        $this->resetInstance();
        $this->CI->load->model('Inventory_model');
        $this->obj = $this->CI->Inventory_model;
    }

    public function test_get_category_list()
    {
        $expected = [
            1 => 'Book',
            2 => 'CD',
            3 => 'DVD',
        ];
        $list = $this->obj->get_category_list();
        foreach ($list as $category) {
            $this->assertEquals($expected[$category->id], $category->name);
        }
    }

    public function test_get_category_name()
    {
        $actual = $this->obj->get_category_name(1);
        $expected = 'Book';
        $this->assertEquals($expected, $actual);
    }
}

As an example, a test case class for Welcome controller would be as follows:

<?php

class Welcome_test extends TestCase
{
    public function test_index()
    {
        $output = $this->request('GET', 'welcome/index');
        $this->assertStringContainsString(
            '<title>Welcome to CodeIgniter</title>', $output
        );
    }
}

See How to Write Tests for details.

Function/Class Reference

See Function and Class Reference.

Tips

See Tips.

Stand-alone Packages

Some features of ci-phpunit-test are available in the following standalone packages.

Related Projects for CodeIgniter 3.x