Codeception Testing framework is a great utility for testing PHP applications. Codeception is inspired by BDD style, and can be effectively used in writing acceptance,functional and unit tests as well that’s mostly written by developers to test their PHP code.
Usage of Codeception Framework:
- Cross Browser testing: Functional tests written in codeception can be executed to check the consistency among different browsers like Firefox, Chrome, IE-versions. It can also be executed using Cloud testing services with Selenium WebDriver.
- API Testing: Codeception simplifies REST and SOAP testing. There are flexible commands to test structure and data of JSON and XML responses. Testing can be done over HTTP or inside a framework.
- Unit and Integration Testing: Codeception is built on top of PHPUnit and is able to execute its tests. Integration tests can be improved with commands for database interactions.
- Acceptance Tests: Acceptance tests are presented as a set of end-user actions and these are written in a simplified English-like language, which can then be converted into a scenario based UAT test. Codeception provides high-level domain language for these types of user-acceptance tests.
How To write Acceptance Tests using Codeception:
Acceptance testing can be performed by a non-technical person. It simply emulates a series of actions performed by an end user. For example, “open a web page, enter the Login credentials and navigate to the Welcome page of an application”
Sample Acceptance test code snippet for the above scenario:
<?php $I->amOnPage('/login'); $I->fillField('username', 'davert'); $I->fillField('password', 'qwerty'); $I->click('LOGIN'); $I->see('Welcome, Davert!');
The above code explains a end-user entering his user name/pwd and clicking on the login button and navigates to the Welcome page after the “click” action
We will run the above PHP code with a local copy of the site running on the host. We need to specify the url parameter in the acceptance suite config (tests/acceptance.suite.yml) as below:
class_name: AcceptanceTester modules: enabled: - PhpBrowser: url: - HelperAcceptance
The $I object used in the acceptance test code is used to write all interactions. The methods of the $I object are taken from the PhpBrowser module.
Codeception Modules and Helpers
All actions and assertions that are to be performed by the tester object in a class should be defined in modules. Modules allow you to choose the actions and assertions that can be performed in tests.
Let’s take a look at the below code snippet:
<?php $I = new FunctionalTester($scenario); $I->amOnPage('/'); $I->see('Hello'); $I->seeInDatabase('users', array('id' => 1)); $I->seeFileFound('running.lock'); ?>
In the above code, the web page can be loaded with the PhpBrowser module, the database assertion uses the Db module, and file state can be checked with the Filesystem module.
When we have a long-running test and we want it to run to the end, we can use conditional assertions. Each `see’ method has a corresponding canSee' method, and
dontSee’ has a `cantSee’ method. The method ‘see’ is a hard assert equivalent and the test fails when the condition fails. Modules are attached to Actor classes in the suite config. For example:
class_name: FunctionalTester modules: enabled: [PhpBrowser, Db, Filesystem]
In the above snippet, The FunctionalTester class has its methods defined in modules. It knows which module executes this action and passes parameters into it.
Helpers
Codeception does not restrict you to only the modules from the main repository. By running the bootstrap command, Codeception generates three dummy modules,one for each of the newly created suites. These custom modules are called ‘Helpers’, and they can be found in the tests/_support directory.
Helpers class names must end with “*Helper.php”
For example, if we want to extend the FunctionalHelper class, by default it will belinked with a FunctionalTester class and functional test suite.
<?php namespace CodeceptionModule; // Define custom functions
class FunctionalHelper extends CodeceptionModule
{
}
?>
Every action we define is a public function. Public methods prefixed by _ are treated as hidden and won’t be added to the Actor class.
We can define asserts by using assertXXX methods in modules. Not all PHPUnit assert methods are included in modules, but we can use PHPUnit static methods from the PHPUnit_Framework_Assert class to leverage all of them.
<?php
function seeClassExist($class)
{
$this->assertTrue(class_exists($class));
// or
PHPUnit_Framework_Assert::assertTrue(class_exists($class));
}
?>
In the helpers we can use these assertions:
<?php
function seeCanCheckEverything($thing)
{
$this->assertTrue(isset($thing), “this thing is set”);
$this->assertFalse(empty($any), “this thing is not empty”);
$this->assertNotNull($thing, “this thing is not null”);
$this->assertContains(“world”, $thing, “this thing contains ‘world'”);
$this->assertNotContains(“bye”, $thing, “this thing doesn`t contain ‘bye'”);
$this->assertEquals(“hello world”, $thing, “this thing is ‘Hello world’!”);
// …
}
Locators in Codeception framework:
Codeception tries to locate an element by its text, name, CSS or XPath. You can specify the locator type manually by passing an array as a parameter. We call this a strict locator. Available strict locator types are:
Id, name, css, xpath, link and class
Example:
<?php // By specifying locator type $I->click(['link' => 'Login']); $I->click(['class' => 'btn']);
There is also a special class CodeceptionUtilLocator which will help us to generate complex XPath locators. For instance, it can easily allow us to click an element on the last row of a table:
This gives us a brief idea on how we can leverage the advantages of using codeception framework with PHP in BDD style
Pros and Cons of Codeception:
Pros:
- can be run on any website
- can test JavaScript and AJAX requests
- most stable in support: less affected by changes in source code or technologies
Cons:
- the slowest: requires running browser and database repopulation
- fewer checks may lead to false-positive results
- not stable in execution: rendering and JavaScript issues can lead to unpredictable results.