Codeception provides high-level domain language for tests. Tests are represented as a set of user's actions.
$I->amOnPage('/'); ⇒ I am on page '/'
$I->click('Enter'); ⇒ I click 'Enter'
$I->see('Welcome'); ⇒ I see 'Welcome'Tests can be executed using Firefox, Chrome, PhantomJS or Cloud Testing services with Selenium WebDriver. Browser can be emulated with HTTP-requests through CURL with PhpBrowser.
$I->amOnPage('/login');
$I->fillField('username', 'davert');
$I->fillField('password', 'qwerty');
$I->click('LOGIN');
$I->see('Welcome, Davert!');Tests can be executed inside a PHP framework. This way web application can be executed without web server to running faster and accessing application internals. Silex, Symfony, Laravel, Zend, Yii, Phalcon are supported.
modules:
enabled:
- Silex:
app: 'app/bootstrap.php'
<?php
$app = require __DIR__.'/path/to/app.php';
$app['debug'] = true;
unset($app['exception_handler']);
return $app; // optionallyBDD is aimed to establish one language between development, QA, and business teams. Codeception can execute feature files written in Gherkin format as tests.
Feature: checkout process
In order to buy products
As a customer
I want to be able to buy several products
Scenario:
Given I have product with $600 price in my cart
And I have product with $1000 price
When I go to checkout process
Then I should see that total number of products is 2
And my order amount is $1600Codeception is built on top of PHPUnit and is able to execute its tests. Integration tests can be improved with commands for database interactions.
<?php
class UserTest extends \Codeception\Test\Unit
{
public function testValidation()
{
$user = User::create();
$user->username = null;
$this->assertFalse($user->validate(['username']));
}
}
....With the power of Aspect Oriented programming and the awesome Go-AOP library, AspectMock allows you to stub and mock practically anything in your PHP code!
$ar = test::double('ActiveRecord', ['save' => null]);
$user = new User;
$user->name = 'davert';
$user->save(); // passes to ActiveRecord->save() and does not insert any SQL.
$ar->verifyInvoked('save'); // true
--------------
namespace demo;
test::func('demo', 'time', 'now');
$this->assertEquals('now', time());
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.
$I->haveHttpHeader('X-Requested-With', 'Codeception');
$I->sendGET('test-headers.php');
$I->seeResponseCodeIs(200);
$I->seeResponseContainsJson(array('name' => 'john'));
$I->seeResponseJsonMatchesJsonPath('$.store.book[*].author');
...
$I->deleteHeader('X-Requested-With');
$I->sendPOST('some-other-page.php');// install
composer require "codeception/codeception" --dev
// create test project path with helpers
codecept bootstrap
// generate first test
codecept generate:cest acceptance First
// acceptance.suite.yml:
actor: AcceptanceTester
modules:
enabled:
- PhpBrowser:
url: http://localhost
- \Helper\Acceptance
// first test
<?php
class FirstCest
{
public function frontpageWorks(AcceptanceTester $I)
{
$I->amOnPage('/');
$I->see('Home');
}
}// api.suite.yml
actor: ApiTester
modules:
enabled:
- REST:
url: http://serviceapp/api/v1/
depends: PhpBrowser
part: Json
// generate test
codecept generate:cept api CreateUser
// write a test
<?php
$I = new ApiTester($scenario);
$I->wantTo('create a user via API');
$I->amHttpAuthenticated('service_user', '123456');
$I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded');
$I->sendPOST('/users', ['name' => 'davert', 'email' => 'davert@codeception.com']);
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200
$I->seeResponseIsJson();
$I->seeResponseContains('{"result":"ok"}');
$I->seeResponseContainsJson(['result' => 'ok']);
$I->seeResponseJsonMatchesJsonPath('$[0].user.login');
$I->seeResponseJsonMatchesXpath('//user/login');
$I = new FunctionalTester($scenario);
$I->wantTo('create wiki page');
$I->amOnPage('/');
$I->click('Pages');
$I->click('New');
$I->wait(3); // wait for 3 secs
$I->see('New Page');
$I->submitForm('form#new_page', array('title' => 'Tree of Life Movie Review','body' => "Next time don't let Hollywood create art-house!"));
$I->see('page created'); // notice generated
$I->see('Tree of Life Movie Review','h1'); // head of page of is our title
$I->seeInCurrentUrl('pages/tree-of-life-movie-review'); // slug is generated
$I->seeInDatabase('pages', array('title' => 'Tree of Life Movie Review')); // data is stored in database// soap.suite.yml
actor: ApiTester
modules:
enabled:
- SOAP:
depends: PhpBrowser
endpoint: http://serviceapp/api/v1/
<?php
$I->haveSoapHeader('Auth', array('username' => 'Miles', 'password' => '123456'));
<soap:Header>
<Auth>
<username>Miles</username>
<password>123456</password>
</Auth>
</soap:Header>
<?php
$I->sendSoapRequest('CreateUser', '<name>Miles Davis</name><email>miles@davis.com</email>');
<soap:Body>
<ns:CreateUser>
<name>Miles Davis</name>
<email>miles@davis.com</email>
</ns:CreateUser>
</soap:Body>
<?php
$I->seeSoapResponseEquals('<?xml version="1.0"<error>500</error>');
$I->seeSoapResponseIncludes('<result>1</result>');
$I->seeSoapResponseContainsStructure('<user><name></name><email></email>');
$I->seeSoapResponseContainsXPath('//result/user/name[@id=1]');
<?php
use \Codeception\Util\Xml;
$I = new ApiTester($scenario);
$I->wantTo('create user');
$I->haveSoapHeader('Session', array('token' => '123456'));
$I->sendSoapRequest('CreateUser', Xml::build()
->user->email->val('miles@davis.com'));
$I->seeSoapResponseIncludes(Xml::build()
->result->val('Ok')
->user->attr('id', 1)
);
<?php
namespace Helper;
class Api extends \Codeception\Module {
public function seeResponseIsValidOnSchema($schema)
{
$response = $this->getModule('SOAP')->response;
$this->assertTrue($response->schemaValidate($schema));
}
}