This document discusses automated testing with Codeception. It introduces test-driven development (TDD) and its benefits. Codeception allows running different types of tests (acceptance, functional, unit) from one place. Installing and using Codeception for testing Drupal is described, including generating tests, running tests, using Selenium WebDriver, cleaning up databases, and reusing test code with step objects and page objects.
3. TEST DRIVEN DEVELOPMENT
1. Write a test
2. Run the test
3. Let the test fail
4. Write enough code for the test to pass
5. Run your test again
6. Refactor/ clean up the code
7. Run test again
8. Repeat
4. WHY USE TDD
1. Better understanding of what you're going to write
2. Enforces the policy of writing tests a little better
3. Speeds up development
5. BENEFITS OF TDD
1. Testable code
2. Clean design
3. Able to be refactored with confidence
4. The minimal code necessary to satisfy the story card
5. A living specification of how the code works
6. Able to support a sustainable pace of new features
7. WHY USE CODECEPTION
1. Powered by PHPUnit
2. Any type of test
a. Acceptance
b. Functional
c. Unit
3. Easy to extend
4. Lot of test suits already available for Drupal
5. Reusable code
6. Run all types of test from one place
10. GETTING STARTED
By default AcceptanceTester relies on PhpBrowser module, which is set in
tests/acceptance.suite.yml
It can also be set to use WebDriver
class_name: WebGuyTester
modules:
enabled:
- WebDriver:
url: http://drupal812
browser: chrome
wait: 2000
- HelperWebGuy
11. ➜ php codecept.phar generate:cept acceptance Signin
Test was created in /Users/prachi.nagpal/Sites/drupal8/tests/acceptance/SigninCept.php
<?php
$I = new AcceptanceTester($scenario);
$I->wantTo('Test index page');
$I->amOnPage('/');
$I->see('Site-Install','#header #site-name');
$I->amGoingTo('login in the test app');
$I->fillField('Username','admin');
$I->fillField('Password','1234');
$I->click('Log in');
$I->see('Log out');
$I->click('Log out');
$I->see('User login');
?>
12. EXAMPLE
<?php
$I = new AcceptanceTester($scenario);
$I->wantTo('ensure that frontpage works');
$I->amOnPage('/');
$I->see('Home');
?>
<?php
$I = new AcceptanceTester($scenario);
$I->amOnPage('/');
$I->click('Sign Up');
$I->submitForm('#signup', ['username' => prachi.nagpal, 'email' => 'prachi.nagpal@acquia.com']);
$I->see('Thank you for Signing Up!');
?>
13. EXAMPLE
Codeception can even 'naturalize' this scenario, converting it into plain English:
I WANT TO SIGN IN
I am on page '/user'
I fill field 'username', 'prachi.nagpal'
I fill field 'password', '1234'
I click 'Log in'
I see 'Welcome, prachi.nagpal!'
14. RUNNING TESTS
Tests can be started with the run command.
➜ php codecept.phar run
➜ php codecept.phar run acceptance
➜ php codecept.phar run acceptance SigninCept.php
➜ php codecept.phar run tests/acceptance/SigninCept.php
➜ php codecept.phar run tests/acceptance/SignInCest.php:anonymousLogin
➜ php codecept.phar run tests/acceptance/backend
15. SELENIUM WEBDRIVER
WAIT
<?php
$I->waitForElement('#agree_button', 30); // secs
$I->click('#agree_button');
?>
SESSION SNAPSHOTS
function test_login($I) {
// if snapshot exists - skipping login
if ($I->loadSessionSnapshot('login')) return;
// logging in
$I->amOnPage('/login');
$I->click('Login');
// saving snapshot
$I->saveSessionSnapshot('login');
}
// in test:
$I = new AcceptanceTester($scenario);
test_login($I);
17. CLEANING UP / DB SNAPSHOTS
→ Db module
→ Load a database dump after each passed test.
→ SQL dump to be put in /tests/_data directory.
→ Set the database connection and path to the dump in the global Codeception config.
# in codeception.yml:
modules:
config:
Db:
dsn: '[set pdo dsn here]'
user: '[set user]'
password: '[set password]'
dump: tests/_data/dump.sql
19. REUSING TEST CODE
StepObjects
➜ php codecept.phar generate:stepobject acceptance Admin
➜ php codecept.phar generate:stepobject acceptance Admin
Add action to StepObject class (ENTER to exit): loginAsAdmin
Add action to StepObject class (ENTER to exit):
StepObject was created in /tests/acceptance/_support/Step/Acceptance/Admin.php
20. Step Object
<?php
namespace StepAcceptance;
class Member extends AcceptanceTester
{
public function loginAsAdmin()
{
$I = $this;
$I->amOnPage('/admin');
$I->fillField('username', 'admin');
$I->fillField('password', '123456');
$I->click('Login');
}
}
?>
Actual Test
<?php
use Step/Acceptance/Admin as AdminTester;
$I = new AdminTester($scenario);
$I->loginAsAdmin();
?>
21. PageObjects
$ php codecept.phar generate:pageobject Login
Defining PageObjects
<?php
namespace Page;
class Login
{
public static $URL = '/login';
public static $usernameField = '#mainForm #username';
public static $passwordField = '#mainForm input[name=password]';
public static $loginButton = '#mainForm input[type=submit]';
}
?>
22. Using PageObjects
<?php
use PageLogin as LoginPage;
$I = new AcceptanceTester($scenario);
$I->wantTo('login to site');
$I->amOnPage(LoginPage::$URL);
$I->fillField(LoginPage::$usernameField, 'bill evans');
$I->fillField(LoginPage::$passwordField, 'debby');
$I->click(LoginPage::$loginButton);
$I->see('Welcome, bill');
?>