Now you can write tests for CodeIgniter 3.0 apps that contains exit() with ci-phpunit-test

If you have apps that contains exit() or die(), normally you can't test them with PHPUnit.

Because an exit() in your app will abort the whole test suite.

But if you use CI PHPUnit Test v0.5.0, you can test your CodeIgniter apps like that without any modifications.

(2016/02/28 Added) If you are not familiar with Testing, I recommend our Ebook. CodeIgniter Testing Guide. It is Beginners' Guide to Automated Testing in PHP.

Requirements

  • CodeIgniter 3.0
  • PHP 5.4 or later
  • PHPUnit (4.7 is recommended)
  • ci-phpunit-test v0.5.0 (or later)

Setup

Installing CI PHPUnit Test is very easy.

Step 0

Install CodeIgniter 3.0.0. Download CodeIgniter 3.0.0 from http://www.codeigniter.com/download and unzip it.

Step 1

Install CI PHPUnit Test. Download latest version from https://github.com/kenjis/ci-phpunit-test/releases and unzip it. Copy application/tests folder into application folder.

CodeIgniter-3.0.0/
└── application/
    └── tests/

Step 2

Install PHPUnit 4.7. See https://phpunit.de/manual/4.7/en/installation.html.

For example, download https://phar.phpunit.de/phpunit.phar, and copy it to CodeIgniter project application/tests folder.

CodeIgniter-3.0.0/
└── application/
    └── tests/
        └── phpunit.phar

Now you're ready to run phpuint tests.

$ cd CodeIgniter-3.0.0/application/tests/
$ php phpunit.phar 
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.

...

Time: 896 ms, Memory: 9.25Mb

OK (3 tests, 3 assertions)

Generating code coverage report in Clover XML format ... done

Generating code coverage report in HTML format ... done

Okay.

Application Code containing exit()

If you have a controller like this:

application/controllers/Test.php

<?php

class Test extends CI_Controller
{
    public function index()
    {
        $this->output
            ->set_status_header(200)
            ->set_content_type('application/json', 'utf-8')
            ->set_output(json_encode(['foo' => 'bar']))
            ->_display();
        exit();
    }
}

You can write a test case with CI PHPUnit Test like below:

application/tests/controllers/Test_test.php

<?php

class Test_test extends TestCase
{
    public function test_index()
    {
        $output = $this->request('GET', 'test/index');
        $this->assertContains('{"foo":"bar"}', $output);
    }
}

But when phpunit runs Test controller, the whole test suite will be aborted by the exit() in the controller like below:

$ php phpunit.phar 
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.

{"foo":"bar"}$ 

There is no test results. So you can't test the controller normally.

Converting exit() to Exception

But now CI PHPUnit Test has a new functionality to convert exit() to exception.

To enable it, you just change TestCase::$enable_patcher to true.

(2015/08/12 Added) The way to enable this functionality has changed on CI PHPUnit Test v0.6.0. See https://github.com/kenjis/ci-phpunit-test/blob/master/docs/HowToWriteTests.md#monkey-patching.

--- a/application/tests/TestCase.php
+++ b/application/tests/TestCase.php
@@ -2,5 +2,5 @@

 class TestCase extends CIPHPUnitTestCase
 {
-   public static $enable_patcher = false;
+   public static $enable_patcher = true;
 }

Let's run phpunit again.

$ php phpunit.phar 
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.

E...

Time: 1.23 seconds, Memory: 10.50Mb

There was 1 error:

1) Test_test::test_index
CIPHPUnitTestExitException: exit() called in Test::index()

/Users/kenji/CodeIgniter-3.0.0/application/controllers/Test.php:12
/Users/kenji/CodeIgniter-3.0.0/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:281
/Users/kenji/CodeIgniter-3.0.0/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:243
/Users/kenji/CodeIgniter-3.0.0/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:87
/Users/kenji/CodeIgniter-3.0.0/application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php:60
/Users/kenji/CodeIgniter-3.0.0/application/tests/controllers/Test_test.php:7
/Users/kenji/CodeIgniter-3.0.0/application/tests/phpunit.phar:537

FAILURES!
Tests: 4, Assertions: 3, Errors: 1.

Generating code coverage report in Clover XML format ... done

Generating code coverage report in HTML format ... done

Now you can see an error message below:

1) Test_test::test_index
CIPHPUnitTestExitException: exit() called in Test::index()

Yes, exit() was converted to CIPHPUnitTestExitException.

Cool, isn't it?

So you can test it to catch the exception.

application/tests/controllers/Test_test.php

<?php

class Test_test extends TestCase
{
    public function test_index()
    {
        try {
            $output = $this->request('GET', 'test/index');
        } catch (CIPHPUnitTestExitException $e) {
            $output = ob_get_clean();
        }
        $this->assertContains('{"foo":"bar"}', $output);
    }
}

Let's run phpunit again.

$ php phpunit.phar 
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.

....

Time: 1.34 seconds, Memory: 10.50Mb

OK (4 tests, 4 assertions)

Generating code coverage report in Clover XML format ... done

Generating code coverage report in HTML format ... done

Okay. All green.

Summary

  • Installing CI PHPUnit Test is very easy. You don't have to modify CodeIgniter files at all.
  • You can write tests for application code that contains exit() or die() with CI PHPUnit Test.

If you are interested in CI PHPUnit Test, see the official site:

Date: 2015/07/27

Tags: english