tests/models/Inventory_model_test.php
<?php
class Inventory_model_test extends TestCase
{
public function setUp()
{
$this->CI =& get_instance();
$this->CI->load->model('shop/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);
}
}Test case class extends TestCase class.
Don't forget to write parent::setUpBeforeClass(); if you override setUpBeforeClass() method.
See working sample.
I put Seeder Library and a sample Seeder File.
They are not installed, so if you want to use, copy them manually.
You can use them like below:
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
$CI =& get_instance();
$CI->load->library('Seeder');
$CI->seeder->call('CategorySeeder');
}See working sample.
You can use $this->getMockBuilder() method in PHPUnit and $this->verifyInvoked*() helper methods in CI PHPUnit Test.
public function setUp()
{
$this->CI =& get_instance();
$this->CI->load->model('Category_model');
$this->obj = $this->CI->Category_model;
}
public function test_get_category_list()
{
// Create mock objects for CI_DB_pdo_result and CI_DB_pdo_sqlite_driver
$return = [
0 => (object) ['id' => '1', 'name' => 'Book'],
1 => (object) ['id' => '2', 'name' => 'CD'],
2 => (object) ['id' => '3', 'name' => 'DVD'],
];
$db_result = $this->getMockBuilder('CI_DB_pdo_result')
->disableOriginalConstructor()
->getMock();
$db_result->method('result')->willReturn($return);
$db = $this->getMockBuilder('CI_DB_pdo_sqlite_driver')
->disableOriginalConstructor()
->getMock();
$db->method('get')->willReturn($db_result);
// Verify invocations
$this->verifyInvokedOnce(
$db_result,
'result',
[]
);
$this->verifyInvokedOnce(
$db,
'order_by',
['id']
);
$this->verifyInvokedOnce(
$db,
'get',
['category']
);
// Replace property db with mock object
$this->obj->db = $db;
$expected = [
1 => 'Book',
2 => 'CD',
3 => 'DVD',
];
$list = $this->obj->get_category_list();
foreach ($list as $category) {
$this->assertEquals($expected[$category->id], $category->name);
}
// Reset CI object for next test case, unless property db won't work
reset_instance();
new CI_Controller();
}See working sample.
You can use $this->request() method in CI PHPUnit Test.
tests/controllers/Welcome_test.php
<?php
class Welcome_test extends TestCase
{
public function test_index()
{
$output = $this->request('GET', ['Welcome', 'index']);
$this->assertContains('<title>Welcome to CodeIgniter</title>', $output);
}
}See working sample.
public function test_uri_sub_sub_index()
{
$output = $this->request('GET', 'sub/sub/index');
$this->assertContains('<title>Page Title</title>', $output);
}See working sample.
You can use $this->ajaxRequest() method in CI PHPUnit Test.
public function test_index_ajax_call()
{
$output = $this->ajaxRequest('GET', ['Ajax', 'index']);
$expected = '{"name": "John Smith", "age": 33}';
$this->assertEquals($expected, $output);
}See working sample.
I recommend to use symfony/dom-crawler.
$output = $this->request('GET', ['Welcome', 'index']);
$crawler = new Symfony\Component\DomCrawler\Crawler($output);
// Get the text of the first <h1>
$text = $crawler->filter('h1')->eq(0)->text();See working sample.
I recommend to use PHPUnit mock objects. $this->getDouble() is a helper method in CI PHPUnit Test.
public function test_index_logged_in()
{
$inject_ion_auth = function ($CI) {
// Get mock object
$auth = $this->getDouble(
'Ion_auth', ['logged_in' => TRUE, 'is_admin' => TRUE]
);
// Inject mock object
$CI->ion_auth = $auth;
};
$output = $this->request('GET', ['Auth', 'index'], [], $inject_ion_auth);
$this->assertContains('<p>Below is a list of the users.</p>', $output);
}See working sample.
I recommend to use this MY_url_helper.php.
If you use it, you can write tests like this:
/**
* @expectedException PHPUnit_Framework_Exception
* @expectedExceptionCode 302
* @expectedExceptionMessageRegExp !\ARedirect to http://localhost/login\z!
*/
public function test_index()
{
$output = $this->request('GET', ['Admin', 'index']);
}See working sample.
If you have two controllers with the exact same name, PHP Fatal error stops PHPUnit testing.
In this case, you can use PHPUnit annotations @runInSeparateProcess and @preserveGlobalState disabled. But tests in a separate PHP process are very slow.
tests/controllers/sub/Welcome_test.php
<?php
class sub_Welcome_test extends TestCase
{
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function test_uri_sub_welcome_index()
{
$output = $this->request('GET', 'sub/welcome/index');
$this->assertContains('<title>Page Title</title>', $output);
}
}See working sample.
show_error() and show_404() in CI PHPUnit Test throw PHPUnit_Framework_Exception.
/**
* @expectedException PHPUnit_Framework_Exception
* @expectedExceptionCode 404
*/
public function test_index()
{
$output = $this->request('GET', ['nocontroller', 'noaction']);
}See working sample.
You can put mock libraries in tests/mocks/libraries folder. You can see application/tests/mocks/libraries/email.php as a sample.
With mock libraries, you could replace your object in CodeIgniter instance.
This is how to replace Email library with Mock_Libraries_Email class.
public function setUp()
{
$this->CI =& get_instance();
$this->CI->load->model('Mail_model');
$this->obj = $this->CI->Mail_model;
$this->CI->email = new Mock_Libraries_Email();
}Mock library class name must be Mock_Libraries_*, and it is autoloaded.
Want to see more tests?