From 440aafde4b00f29545b4faa2fa6b55e28cac956e Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 1 Jul 2020 15:35:22 +0000 Subject: [PATCH 1/3] Add test case default mocking --- system/Test/CIUnitTestCase.php | 92 +++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index b403b7b64cff..ae13340cd273 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -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; /** @@ -55,7 +59,38 @@ class CIUnitTestCase extends TestCase */ protected $app; - protected function setUp(): void + /** + * Callbacks to run during setUp. + * + * @var array of methods + */ + protected $setUpMethods = [ + 'mockEmail', + 'mockSession', + ]; + + /** + * Callbacks to run during tearDown. + * + * @var array of methods + */ + protected $tearDownMethods = []; + + //-------------------------------------------------------------------- + // Staging + //-------------------------------------------------------------------- + + /** + * Load the helpers. + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + helper(['url', 'test']); + } + + public function setUp(): void { parent::setUp(); @@ -64,9 +99,51 @@ protected function setUp(): void $this->app = $this->createApplication(); } - helper('url'); + foreach ($this->setUpMethods as $method) + { + $this->$method(); + } + } + + public 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. @@ -236,6 +313,10 @@ public function assertCloseEnoughString($expected, $actual, string $message = '' } } + //-------------------------------------------------------------------- + // Utility + //-------------------------------------------------------------------- + /** * Loads up an instance of CodeIgniter * and gets the environment setup. @@ -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; @@ -279,5 +358,4 @@ protected function getHeaderEmitted(string $header, bool $ignoreCase = false): ? return null; } - } From ea468878b5c15407f2f6e99a8929d2d35807d472 Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 1 Jul 2020 15:52:29 +0000 Subject: [PATCH 2/3] Add test staging docs --- system/Test/CIUnitTestCase.php | 4 +- user_guide_src/source/testing/overview.rst | 47 +++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index ae13340cd273..8278fe5102d6 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -60,7 +60,7 @@ class CIUnitTestCase extends TestCase protected $app; /** - * Callbacks to run during setUp. + * Methods to run during setUp. * * @var array of methods */ @@ -70,7 +70,7 @@ class CIUnitTestCase extends TestCase ]; /** - * Callbacks to run during tearDown. + * Methods to run during tearDown. * * @var array of methods */ diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 96646d62e194..d7b1ba0767ba 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -101,6 +101,51 @@ have the correct namespace relative to ``App``. When testing database results, you must use the `CIDatabaseTestClass `_ 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 --------------------- @@ -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 ============== From d93abf4ddfb476c90b9ecd51837832fea2d7574c Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 1 Jul 2020 17:49:01 +0000 Subject: [PATCH 3/3] Correct the scope on fixture methods --- system/Test/CIUnitTestCase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 8278fe5102d6..d90b2e08327e 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -90,7 +90,7 @@ public static function setUpBeforeClass(): void helper(['url', 'test']); } - public function setUp(): void + protected function setUp(): void { parent::setUp(); @@ -105,7 +105,7 @@ public function setUp(): void } } - public function tearDown(): void + protected function tearDown(): void { parent::tearDown();