Skip to content

Commit

Permalink
Merge pull request #3193 from MGatner/automock
Browse files Browse the repository at this point in the history
Test Case Mocking
  • Loading branch information
MGatner authored Jul 2, 2020
2 parents effa61b + d93abf4 commit dbadbaa
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 7 deletions.
90 changes: 84 additions & 6 deletions system/Test/CIUnitTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
namespace CodeIgniter\Test;

use CodeIgniter\Events\Events;
use CodeIgniter\Session\Handlers\ArrayHandler;
use CodeIgniter\Test\Mock\MockEmail;
use CodeIgniter\Test\Mock\MockSession;
use Config\Services;
use PHPUnit\Framework\TestCase;

/**
Expand All @@ -55,6 +59,37 @@ class CIUnitTestCase extends TestCase
*/
protected $app;

/**
* Methods to run during setUp.
*
* @var array of methods
*/
protected $setUpMethods = [
'mockEmail',
'mockSession',
];

/**
* Methods to run during tearDown.
*
* @var array of methods
*/
protected $tearDownMethods = [];

//--------------------------------------------------------------------
// Staging
//--------------------------------------------------------------------

/**
* Load the helpers.
*/
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();

helper(['url', 'test']);
}

protected function setUp(): void
{
parent::setUp();
Expand All @@ -64,9 +99,51 @@ protected function setUp(): void
$this->app = $this->createApplication();
}

helper('url');
foreach ($this->setUpMethods as $method)
{
$this->$method();
}
}

protected function tearDown(): void
{
parent::tearDown();

foreach ($this->tearDownMethods as $method)
{
$this->$method();
}
}

//--------------------------------------------------------------------
// Mocking
//--------------------------------------------------------------------

/**
* Injects the mock session driver into Services
*/
protected function mockSession()
{
$_SESSION = [];

$config = config('App');
$session = new MockSession(new ArrayHandler($config, '0.0.0.0'), $config);

Services::injectMock('session', $session);
}

/**
* Injects the mock email driver so no emails really send
*/
protected function mockEmail()
{
Services::injectMock('email', new MockEmail(config('Email')));
}

//--------------------------------------------------------------------
// Assertions
//--------------------------------------------------------------------

/**
* Custom function to hook into CodeIgniter's Logging mechanism
* to check if certain messages were logged during code execution.
Expand Down Expand Up @@ -236,6 +313,10 @@ public function assertCloseEnoughString($expected, $actual, string $message = ''
}
}

//--------------------------------------------------------------------
// Utility
//--------------------------------------------------------------------

/**
* Loads up an instance of CodeIgniter
* and gets the environment setup.
Expand All @@ -247,16 +328,14 @@ protected function createApplication()
return require realpath(__DIR__ . '/../') . '/bootstrap.php';
}

//--------------------------------------------------------------------
/**
* Return first matching emitted header.
*
* @param string $header Identifier of the header of interest
* @param bool $ignoreCase
* @param string $header Identifier of the header of interest
* @param boolean $ignoreCase
*
* @return string|null The value of the header found, null if not found
*/
//
protected function getHeaderEmitted(string $header, bool $ignoreCase = false): ?string
{
$found = false;
Expand All @@ -279,5 +358,4 @@ protected function getHeaderEmitted(string $header, bool $ignoreCase = false): ?

return null;
}

}
47 changes: 46 additions & 1 deletion user_guide_src/source/testing/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,51 @@ have the correct namespace relative to ``App``.

When testing database results, you must use the `CIDatabaseTestClass <database.html>`_ class.

Staging
-------

Most tests require some preparation in order to run correctly. PHPUnit's ``TestCase`` provides four methods
to help with staging and clean up::

public static function setUpBeforeClass(): void
public static function tearDownAfterClass(): void
public function setUp(): void
public function tearDown(): void

The static methods run before and after the entire test case, whereas the local methods run
between each test. If you implement any of these special functions make sure you run their
parent as well so extended test cases do not interfere with staging::

public function setUp(): void
{
parent::setUp();
helper('text');
}

In addition to these methods, ``CIUnitTestCase`` also comes with a convenience property for
parameter-free methods you want run during set up and tear down::

protected $setUpMethods = [
'mockEmail',
'mockSession',
];
protected $tearDownMethods = [];

You can see by default these handle the mocking of intrusive services, but your class may override
that or provide their own::

class OneOfMyModelsTest extends CIUnitTestCase
{
protected $tearDownMethods = [
'purgeRows',
];
protected function purgeRows()
{
$this->model->purgeDeleted()
}

Additional Assertions
---------------------

Expand Down Expand Up @@ -262,7 +307,7 @@ class exactly. The second parameter is the instance to replace it with.

Removes all mocked classes from the Services class, bringing it back to its original state.


.. note:: The ``Email`` and ``Session`` services are mocked by default to prevent intrusive testing behavior. To prevent these from mocking remove their method callback from the class property: ``$setUpMethods = ['mockEmail', 'mockSession'];``

Stream Filters
==============
Expand Down

0 comments on commit dbadbaa

Please sign in to comment.