Rebuilding with CodeIgniter 4
This commit is contained in:
parent
e6dcc92267
commit
3bce4ad0ac
92 changed files with 7304 additions and 380 deletions
108
tests/README.md
Normal file
108
tests/README.md
Normal file
|
@ -0,0 +1,108 @@
|
|||
# Running Application Tests
|
||||
|
||||
This is the quick-start to CodeIgniter testing. Its intent is to describe what
|
||||
it takes to set up your application and get it ready to run unit tests.
|
||||
It is not intended to be a full description of the test features that you can
|
||||
use to test your application. Those details can be found in the documentation.
|
||||
|
||||
## Resources
|
||||
* [CodeIgniter 4 User Guide on Testing](https://codeigniter4.github.io/userguide/testing/index.html)
|
||||
* [PHPUnit docs](https://phpunit.readthedocs.io/en/8.3/index.html)
|
||||
|
||||
## Requirements
|
||||
|
||||
It is recommended to use the latest version of PHPUnit. At the time of this
|
||||
writing we are running version 8.5.2. Support for this has been built into the
|
||||
**composer.json** file that ships with CodeIgniter and can easily be installed
|
||||
via [Composer](https://getcomposer.org/) if you don't already have it installed globally.
|
||||
|
||||
> composer install
|
||||
|
||||
If running under OS X or Linux, you can create a symbolic link to make running tests a touch nicer.
|
||||
|
||||
> ln -s ./vendor/bin/phpunit ./phpunit
|
||||
|
||||
You also need to install [XDebug](https://xdebug.org/index.php) in order
|
||||
for code coverage to be calculated successfully.
|
||||
|
||||
## Setting Up
|
||||
|
||||
A number of the tests use a running database.
|
||||
In order to set up the database edit the details for the `tests` group in
|
||||
**app/Config/Database.php** or **phpunit.xml**. Make sure that you provide a database engine
|
||||
that is currently running on your machine. More details on a test database setup are in the
|
||||
*Docs>>Testing>>Testing Your Database* section of the documentation.
|
||||
|
||||
If you want to run the tests without using live database you can
|
||||
exclude @DatabaseLive group. Or make a copy of **phpunit.dist.xml** -
|
||||
call it **phpunit.xml** - and comment out the <testsuite> named "database". This will make
|
||||
the tests run quite a bit faster.
|
||||
|
||||
## Running the tests
|
||||
|
||||
The entire test suite can be run by simply typing one command-line command from the main directory.
|
||||
|
||||
> ./phpunit
|
||||
|
||||
You can limit tests to those within a single test directory by specifying the
|
||||
directory name after phpunit.
|
||||
|
||||
> ./phpunit app/Models
|
||||
|
||||
## Generating Code Coverage
|
||||
|
||||
To generate coverage information, including HTML reports you can view in your browser,
|
||||
you can use the following command:
|
||||
|
||||
> ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m
|
||||
|
||||
This runs all of the tests again collecting information about how many lines,
|
||||
functions, and files are tested. It also reports the percentage of the code that is covered by tests.
|
||||
It is collected in two formats: a simple text file that provides an overview as well
|
||||
as a comprehensive collection of HTML files that show the status of every line of code in the project.
|
||||
|
||||
The text file can be found at **tests/coverage.txt**.
|
||||
The HTML files can be viewed by opening **tests/coverage/index.html** in your favorite browser.
|
||||
|
||||
## PHPUnit XML Configuration
|
||||
|
||||
The repository has a ``phpunit.xml.dist`` file in the project root that's used for
|
||||
PHPUnit configuration. This is used to provide a default configuration if you
|
||||
do not have your own configuration file in the project root.
|
||||
|
||||
The normal practice would be to copy ``phpunit.xml.dist`` to ``phpunit.xml``
|
||||
(which is git ignored), and to tailor it as you see fit.
|
||||
For instance, you might wish to exclude database tests, or automatically generate
|
||||
HTML code coverage reports.
|
||||
|
||||
## Test Cases
|
||||
|
||||
Every test needs a *test case*, or class that your tests extend. CodeIgniter 4
|
||||
provides a few that you may use directly:
|
||||
* `CodeIgniter\Test\CIUnitTestCase` - for basic tests with no other service needs
|
||||
* `CodeIgniter\Test\CIDatabaseTestCase` - for tests that need database access
|
||||
|
||||
Most of the time you will want to write your own test cases to hold functions and services
|
||||
common to your test suites.
|
||||
|
||||
## Creating Tests
|
||||
|
||||
All tests go in the **tests/** directory. Each test file is a class that extends a
|
||||
**Test Case** (see above) and contains methods for the individual tests. These method
|
||||
names must start with the word "test" and should have descriptive names for precisely what
|
||||
they are testing:
|
||||
`testUserCanModifyFile()` `testOutputColorMatchesInput()` `testIsLoggedInFailsWithInvalidUser()`
|
||||
|
||||
Writing tests is an art, and there are many resources available to help learn how.
|
||||
Review the links above and always pay attention to your code coverage.
|
||||
|
||||
### Database Tests
|
||||
|
||||
Tests can include migrating, seeding, and testing against a mock or live<sup>1</sup> database.
|
||||
Be sure to modify the test case (or create your own) to point to your seed and migrations
|
||||
and include any additional steps to be run before tests in the `setUp()` method.
|
||||
|
||||
<sup>1</sup> Note: If you are using database tests that require a live database connection
|
||||
you will need to rename **phpunit.xml.dist** to **phpunit.xml**, uncomment the database
|
||||
configuration lines and add your connection details. Prevent **phpunit.xml** from being
|
||||
tracked in your repo by adding it to **.gitignore**.
|
|
@ -0,0 +1,61 @@
|
|||
<?php namespace Tests\Support\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class ExampleMigration extends Migration
|
||||
{
|
||||
protected $DBGroup = 'tests';
|
||||
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'name' => [
|
||||
'type' => 'varchar',
|
||||
'constraint' => 31,
|
||||
],
|
||||
'uid' => [
|
||||
'type' => 'varchar',
|
||||
'constraint' => 31,
|
||||
],
|
||||
'class' => [
|
||||
'type' => 'varchar',
|
||||
'constraint' => 63,
|
||||
],
|
||||
'icon' => [
|
||||
'type' => 'varchar',
|
||||
'constraint' => 31,
|
||||
],
|
||||
'summary' => [
|
||||
'type' => 'varchar',
|
||||
'constraint' => 255,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'datetime',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'datetime',
|
||||
'null' => true,
|
||||
],
|
||||
'deleted_at' => [
|
||||
'type' => 'datetime',
|
||||
'null' => true,
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addField('id');
|
||||
$this->forge->addField($fields);
|
||||
|
||||
$this->forge->addKey('name');
|
||||
$this->forge->addKey('uid');
|
||||
$this->forge->addKey(['deleted_at', 'id']);
|
||||
$this->forge->addKey('created_at');
|
||||
|
||||
$this->forge->createTable('factories');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('factories');
|
||||
}
|
||||
}
|
40
tests/_support/Database/Seeds/ExampleSeeder.php
Normal file
40
tests/_support/Database/Seeds/ExampleSeeder.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php namespace Tests\Support\Database\Seeds;
|
||||
|
||||
use CodeIgniter\Database\Seeder;
|
||||
|
||||
class ExampleSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$factories = [
|
||||
[
|
||||
'name' => 'Test Factory',
|
||||
'uid' => 'test001',
|
||||
'class' => 'Factories\Tests\NewFactory',
|
||||
'icon' => 'fas fa-puzzle-piece',
|
||||
'summary' => 'Longer sample text for testing',
|
||||
],
|
||||
[
|
||||
'name' => 'Widget Factory',
|
||||
'uid' => 'widget',
|
||||
'class' => 'Factories\Tests\WidgetPlant',
|
||||
'icon' => 'fas fa-puzzle-piece',
|
||||
'summary' => 'Create widgets in your factory',
|
||||
],
|
||||
[
|
||||
'name' => 'Evil Factory',
|
||||
'uid' => 'evil-maker',
|
||||
'class' => 'Factories\Evil\MyFactory',
|
||||
'icon' => 'fas fa-book-dead',
|
||||
'summary' => 'Abandon all hope, ye who enter here',
|
||||
],
|
||||
];
|
||||
|
||||
$builder = $this->db->table('factories');
|
||||
|
||||
foreach ($factories as $factory)
|
||||
{
|
||||
$builder->insert($factory);
|
||||
}
|
||||
}
|
||||
}
|
51
tests/_support/DatabaseTestCase.php
Normal file
51
tests/_support/DatabaseTestCase.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php namespace Tests\Support;
|
||||
|
||||
class DatabaseTestCase extends \CodeIgniter\Test\CIDatabaseTestCase
|
||||
{
|
||||
/**
|
||||
* Should the database be refreshed before each test?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $refresh = true;
|
||||
|
||||
/**
|
||||
* The seed file(s) used for all tests within this test case.
|
||||
* Should be fully-namespaced or relative to $basePath
|
||||
*
|
||||
* @var string|array
|
||||
*/
|
||||
protected $seed = 'Tests\Support\Database\Seeds\ExampleSeeder';
|
||||
|
||||
/**
|
||||
* The path to the seeds directory.
|
||||
* Allows overriding the default application directories.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePath = SUPPORTPATH . 'Database/';
|
||||
|
||||
/**
|
||||
* The namespace(s) to help us find the migration classes.
|
||||
* Empty is equivalent to running `spark migrate -all`.
|
||||
* Note that running "all" runs migrations in date order,
|
||||
* but specifying namespaces runs them in namespace order (then date)
|
||||
*
|
||||
* @var string|array|null
|
||||
*/
|
||||
protected $namespace = 'Tests\Support';
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Extra code to run before each test
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
// Extra code to run after each test
|
||||
}
|
||||
}
|
55
tests/_support/Libraries/ConfigReader.php
Normal file
55
tests/_support/Libraries/ConfigReader.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019-2020 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019-2020 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace Tests\Support\Libraries;
|
||||
|
||||
/**
|
||||
* Class ConfigReader
|
||||
*
|
||||
* An extension of BaseConfig that prevents the constructor from
|
||||
* loading external values. Used to read actual local values from
|
||||
* a config file.
|
||||
*/
|
||||
class ConfigReader extends \Config\App
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
}
|
26
tests/_support/Models/ExampleModel.php
Normal file
26
tests/_support/Models/ExampleModel.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php namespace Tests\Support\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class ExampleModel extends Model
|
||||
{
|
||||
protected $table = 'factories';
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
protected $returnType = 'object';
|
||||
protected $useSoftDeletes = false;
|
||||
|
||||
protected $allowedFields = [
|
||||
'name',
|
||||
'uid',
|
||||
'class',
|
||||
'icon',
|
||||
'summary',
|
||||
];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
|
||||
protected $validationRules = [];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
}
|
32
tests/_support/SessionTestCase.php
Normal file
32
tests/_support/SessionTestCase.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php namespace Tests\Support;
|
||||
|
||||
use CodeIgniter\Session\Handlers\ArrayHandler;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use CodeIgniter\Test\Mock\MockSession;
|
||||
|
||||
class SessionTestCase extends CIUnitTestCase
|
||||
{
|
||||
/**
|
||||
* @var SessionHandler
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->mockSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-loads the mock session driver into $this->session.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected function mockSession()
|
||||
{
|
||||
$config = config('App');
|
||||
$this->session = new MockSession(new ArrayHandler($config, '0.0.0.0'), $config);
|
||||
\Config\Services::injectMock('session', $this->session);
|
||||
}
|
||||
}
|
42
tests/database/ExampleDatabaseTest.php
Normal file
42
tests/database/ExampleDatabaseTest.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Tests\Support\Models\ExampleModel;
|
||||
|
||||
class ExampleDatabaseTest extends \Tests\Support\DatabaseTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Extra code to run before each test
|
||||
}
|
||||
|
||||
public function testModelFindAll()
|
||||
{
|
||||
$model = new ExampleModel();
|
||||
|
||||
// Get every row created by ExampleSeeder
|
||||
$objects = $model->findAll();
|
||||
|
||||
// Make sure the count is as expected
|
||||
$this->assertCount(3, $objects);
|
||||
}
|
||||
|
||||
public function testSoftDeleteLeavesRow()
|
||||
{
|
||||
$model = new ExampleModel();
|
||||
$this->setPrivateProperty($model, 'useSoftDeletes', true);
|
||||
$this->setPrivateProperty($model, 'tempUseSoftDeletes', true);
|
||||
|
||||
$object = $model->first();
|
||||
$model->delete($object->id);
|
||||
|
||||
// The model should no longer find it
|
||||
$this->assertNull($model->find($object->id));
|
||||
|
||||
// ... but it should still be in the database
|
||||
$result = $model->builder()->where('id', $object->id)->get()->getResult();
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
}
|
||||
}
|
18
tests/session/ExampleSessionTest.php
Normal file
18
tests/session/ExampleSessionTest.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
class ExampleSessionTest extends \Tests\Support\SessionTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testSessionSimple()
|
||||
{
|
||||
$this->session->set('logged_in', 123);
|
||||
|
||||
$value = $this->session->get('logged_in');
|
||||
|
||||
$this->assertEquals(123, $value);
|
||||
}
|
||||
}
|
33
tests/unit/HealthTest.php
Normal file
33
tests/unit/HealthTest.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
class HealthTest extends \CodeIgniter\Test\CIUnitTestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testIsDefinedAppPath()
|
||||
{
|
||||
$test = defined('APPPATH');
|
||||
|
||||
$this->assertTrue($test);
|
||||
}
|
||||
|
||||
public function testBaseUrlHasBeenSet()
|
||||
{
|
||||
$env = $config = false;
|
||||
|
||||
// First check in .env
|
||||
if (is_file(HOMEPATH . '.env'))
|
||||
{
|
||||
$env = (bool) preg_grep("/^app\.baseURL = './", file(HOMEPATH . '.env'));
|
||||
}
|
||||
|
||||
// Then check the actual config file
|
||||
$reader = new \Tests\Support\Libraries\ConfigReader();
|
||||
$config = ! empty($reader->baseUrl);
|
||||
|
||||
$this->assertTrue($env || $config);
|
||||
}
|
||||
}
|
Reference in a new issue