SlideShare a Scribd company logo
1 of 56
Download to read offline
TESTING
TYPO3
APPLICATIONS
CODECEPTION PHPUNIT
TRAVIS-CI
2 1 • 1 1 • 1 7
Software
Testing
PHPUnit, PHPCS, Codeception, PHPMD,
PHPStan, PHPLint, PHPCPD, Selenium, ...
2 1 • 1 1 • 1 7
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
D Y N A M I C T E S T I N G
Execution of Code
U N I T T E S T S
F U N C T I O N A L T E S T S
S T A T I C T E S T I N G
Static Code Analysis, Review, No Code Execution
A C C E P T A N C E T E S T S
Functions, Classes, Isolated, No DB!
Complete System, DB, Environment, No real FE
Browser (UI), API, Technology Independent
1 0 0 0 F U N C T I O N A L T E S T S
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
TESTING
TYPO3’S
CORE
9 1 0 0 U N I T T E S T S
C H R I S T I A N K U H N |   L O L L I 4 2
H T T P S : / / T Y P O 3 . C O M / B L O G / T E S T I N G - T Y P O 3 S - C O R E - P A R T - I -
I N F R A S T R U C T U R E /
2 0 0 A C C E P T A N C E T E S T S
CODECEPTION
E L E G A N T A N D E F F I C I E N T
T E S T I N G F O R P H P
<?php
class FirstCest
{
public function frontpageWorks(AcceptanceTester $I)
{
$I->amOnPage('/');
$I->see('Home');
}
}
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
composer require "codeception/codeception" --dev
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
I N S T A L L A T I O N V I A C O M P O S E R
I N S T A L L P H A R G L O B A L L Y
sudo curl -LsS http://codeception.com/codecept.phar -o
/usr/local/bin/codecept
sudo chmod a+x /usr/local/bin/codecept
codecept bootstrap
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
S E T U P
/tests
/acceptance
/functional
/unit
acceptance.suite.yml
functional.suite.yml
unit.suite.yml
codeception.yml
codecept bootstrap
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
S E T U P
T Y P O 3 E X A M P L E 1
EXT:Example
..
/Tests
/Acceptance
/tests
/acceptance
/api
acceptance.suite.yml
api.suite.yml
codeception.yml
/Functional
/Unit
..
EXT:Example
..
/tests
/acceptance
/functional
/unit
acceptance.suite.yml
functional.suite.yml
unit.suite.yml
codeception.yml
..
T Y P O 3 E X A M P L E 2
codecept init api
codecept init acceptance
codeception.yml
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
settings:
colors: true
memory_limit: 1024M
actor_suffix: Tester
extensions:
enabled:
- CodeceptionExtensionRunFailed
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
acceptance.suite.yml
actor: AcceptanceTester
modules:
enabled:
- PhpBrowser:
url: http://localhost:8080/
- HelperAcceptance
codeception.yml (2)
modules:
enabled:
- Db:
dsn: 'mysql:host=localhost;dbname=%CODECEPT_DB_NAME%;charset=utf8'
user: %CODECEPT_DB_USER%
password: %CODECEPT_DB_PASSWORD%
dump: tests/_data/dump.sql
cleanup: true
populate: true
populator: 'mysql -u $user -p$password $dbname < $dump'
reconnect: true
- Asserts
- PortrinoCodeceptionModuleTypo3
depends: Asserts
- REST
depends: PhpBrowser
url: http://%CODECEPT_DOMAIN%/api/
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
G E N E R A T E T E S T S K E L E T O N S
codecept generate:cept acceptance First
<?php
$I = new AcceptanceTester($scenario);
$I->wantTo('perform actions and see result');
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
G E N E R A T E T E S T S K E L E T O N S
codecept generate:cest acceptance First
<?php
class FirstCest
{
public function _before(AcceptanceTester $I)
{
}
public function _after(AcceptanceTester $I)
{
}
public function tryToTest(AcceptanceTester $I)
{
}
}
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
W R I T E T E S T S
<?php
class FirstCest
{
public function frontpageWorks(AcceptanceTester $I)
{
$I->wantTo('Open TYPO3Camp Website');
$I->amOnUrl('https://www.typo3camp-mitteldeutschland.de/');
$I->seeInTitle('TYPO3Camp Mitteldeutschland');
$I->seeElement('.navbar');
}
}
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
R U N T E S T S
codecept run
codecept run --debug
codecept run api
codecept run acceptance FirstCest:frontpageWorks
codecept run tests/acceptance/FirstCest.php::frontpageWorks
codecept run -g fast
codecept run --env chrome
codecept run --xml
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
C O D E C E P T I O N S Y N T A X
$I->click('Login');
$I->fillField('#input-username', 'John Dough');
$I->pressKey('#input-remarks', 'foo');
A C T I O N S
$I->see('Welcome');
$I->seeInTitle('My Company');
$I->seeElement('nav');
$I->dontSeeElement('#error-message');
$this->assertEquals(123, $foo);
A S S E R T I O N S
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
A C T O R S
UnitTester, FunctionalTester, AcceptanceTester
Methods are taken from Codeception Modules
actor: AcceptanceTester
modules:
enabled:
- PhpBrowser:
url: http://localhost/myapp/
- HelperAcceptance
acceptance.suite.yml:
+ high quality
+ less bugs
+ better maintainability
+ easy refactoring
+ fun
P R O
L A U R E N H I L L S L I D E 0 1
- high experience
- high effort
- consequent
C O N T R A
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
T E S T D R I V E N D E V E L O P M E N T ?
UNIT TESTS
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
P H P U N I T O R C O D E C E P T I O N ?
TYPO3 Unit Testing is easier with pure PHPUnit
https://github.com/TYPO3/testing-framework
https://github.com/Nimut/testing-framework
F R A M E W O R K ?
W H E R E ?
EXT:Foo/Tests/Unit/
EXT:Foo/Tests/Unit/ViewHelpers/RenderViewhelperTest.php
EXT:Foo/Tests/Unit/Fixtures/test_data.txt
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
class FooViewHelperTest extends NimutTestingFrameworkTestCaseUnitTestCase
{
protected function setUp()
{
}
protected function tearDown()
{
}
/**
* @test
*/
public function renderNothingWhenNothingToRender()
{
$this->assertEquals(1,1);
}
}
PROPHECY
{
"require-dev": {
"phpspec/prophecy": "~1.0"
}
}
A N D R É W U T T I G
T Y P O 3 U E R G R O U P
D R E S D E N
https://github.com/phpspec/prophecy
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
class FooViewHelperTest extends NimutTestingFrameworkTestCaseUnitTestCase
{
protected function setUp()
{
$environementServiceMock = $this->getMockBuilder(EnvironmentService::class)->setMethods(
[
'isEnvironmentInCliMode'
])->getMock();
$environementServiceMock->expects(static::any())
->method('isEnvironmentInCliMode')
->willReturn(true);
GeneralUtility::setSingletonInstance(
EnvironmentService::class, $environementServiceMock
);
}
}
PHPUnit MockObjects
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
class FooViewHelperTest extends NimutTestingFrameworkTestCaseUnitTestCase
{
protected function setUp()
{
$environmentServiceMock = $this->prophesize(EnvironmentService::class);
$environmentServiceMock->isEnvironmentInCliMode()->willReturn(false);
GeneralUtility::setSingletonInstance(
EnvironmentService::class, $environmentService->reveal()
);
}
Prophecy
FUNCTIONAL TESTS
D B / A P I / P H P B R O W S E R T E S T I N G
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
modules:
enabled:
- Db:
dsn: 'mysql:host=localhost;dbname=%CODECEPT_DB_NAME%;charset=utf8'
user: %CODECEPT_DB_USER%
password: %CODECEPT_DB_PASSWORD%
dump: tests/_data/dump.sql
cleanup: true
populate: true
populator: 'mysql -u $user -p$password $dbname < $dump' #faster ;-)
reconnect: true
Database - Configuration
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
$I->seeInDatabase('fe_users', array('name' => 'Andre', 'email' => 'wuttig@mail.com'));
$I->dontSeeInDatabase('fe_users', array('name' => 'Andre', 'email' => 'wuttig@mail.com'));
$mail = $I->grabFromDatabase('fe_users', 'email', array('name' => 'Andre'));
$I->haveInDatabase('fe_users', array('name' => 'miles', 'email' => 'wuttig@mail.com'));
$I->seeNumRecords(1, 'fe_users', ['name' => 'andre']);
$I->updateInDatabase('fe_users', ['isAdmin' => true], ['email' => 'miles@davis.com']);
Database Testing - Actions / Assertions / Grabbers
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
#!/bin/bash
PASSWORD=$CODECEPT_DB_PASSWORD
HOST=$CODECEPT_DB_HOST
USER=$CODECEPT_DB_USER
DATABASE=$CODECEPT_DB_NAME
DB_FILE=dump.sql
EXCLUDED_TABLES=(
be_sessions
cf_cache_hash
sys_log
...
)
...
Database Testing - Creating Testdata
https://gist.github.com/aWuttig/58599ae722a5a993172b39046ca07d0a
dump.sh
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
modules:
enabled:
- REST:
depends: PhpBrowser
url: 'http://serviceapp/api/v1/'
REST API - Configuration
L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
$I->amHttpAuthenticated('jon_snow', 'targaryen');
$I->haveHttpHeader('X-Requested-With', 'Codeception');
$I->sendGET('user');
$I->sendPOST('/user', 'name' => 'andre'));
$I->sendPUT('/user', array('id' => 123, 'name' => 'andré'));
$I->sendDELETE('/user/123');
REST API - Actions / Assertions / Grabbers
$I->seeResponseCodeIs(200);
$I->seeResponseContains('foo');
$I->seeHttpHeaderOnce('Cache-Control');
$I->seeResponseContainsJson(array('name' => 'john'));
$I->seeResponseJsonMatchesJsonPath('$.data.0.name');
$I->seeResponseMatchesJsonType(['user_id' => 'integer','is_active' => 'boolean']);
Phiremock
https://github.com/mcustiel/phiremock
M O C K H T T P R E Q U E S T
A N D R E S T A P I ´ S
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
Phiremock
extensions:
enabled:
- CodeceptionExtensionPhiremock
config:
CodeceptionExtensionPhiremock:
listen: 127.0.0.1:18080
modules:
enabled:
- Phiremock:
host: 127.0.0.1
port: 18080
resetBeforeEachTest: false
codeception.yml
Phiremock
$I->expectARequestToRemoteServiceWithAResponse(
Phiremock::on(
A::postRequest()
->andUrl(Is::containing('type=1471426941'))
->andBody(Is::sameStringAs($data))
->andHeader(
'Authorization',
Is::equalTo(self::$token)
)
)->then(
Respond::withStatusCode(201)->andBody('')
)
);
ACCEPTANCE TESTING
W E B D R I V E R , R E A L B R O W S E R
Selenium Driver + Chrome
nohup bash -c "java -jar selenium-server-standalone.jar &" && sleep 1; cat nohup.out
- ls -al
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
sleep 3 # give xvfb some time to start
- ls -al
X Window Virtual Framebuffer
wget -c -nc --retry-connrefused --tries=0 https://goo.gl/s4o9Vx -O 
selenium-server-standalone.jar
Selenium Server Standalone
wget -c -nc --retry-connrefused --tries=0
http://chromedriver.storage.googleapis.com/2.31/chromedriver_linux64.zip
unzip -o -q chromedriver_linux64.zip
Chrome Driver
Start Selenium Server
Webdriver - Configuration
modules:
enabled:
- WebDriver:
url: http://%CODECEPT_DOMAIN%
host: localhost
browser: chrome
restart: true
capabilities:
chromeOptions:
args: ["--headless", "--disable-gpu"]
binary: "/usr/bin/google-chrome"
codeception.yml
Webdriver - Action / Assertions
$I->click('Submit');
$I->closeTab();
$I->seeElement('.error');
$I->waitForElement('#agree_button', 30); // secs
$I->waitForText('foo', 30);
$I->switchToIFrame("another_frame");
$I->setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3');
$I->selectOption('form select[name=account]', 'Premium');
$I->resizeWindow(800, 600);
$I->scrollTo(['css' => '.checkout'], 20, 50);
$I->pressKey('#page','a');
$I->makeScreenshot('edit_page');
$myVar = $I->executeJS('return $("#myField").val()');
Page
Object
Pattern
http://codeception.com/docs/06-
ReusingTestCode#PageObjects
Reuse your testcode
Page Object Pattern
namespace Page;
class LoginPage
{
public static $URL = '/login';
public static $usernameField = '#mainForm #username';
public static $passwordField = '#mainForm input[name=password]';
public static $loginButton = '#mainForm input[type=submit]';
public function login($username, $password) {
$this->tester->fillField(self::$usernameField, $username);
$this->tester->fillField(self::$passwordField, $password);
$this->tester->click(self::$loginButton);
return $this;
}
}
Page Object Pattern
class LoginCest
{
public function loginAsUser(AcceptanceTester $I, LoginPage $loginPage) {
$loginPage->open()->login('wuttig','123456');
$I->seeElement('#userprofile');
}
}
Webdriver - Action / Assertions
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]';
public function login($username, $password) {
$this->tester->fillField(self::$usernameField, $username);
$this->tester->fillField(self::$passwordField, $password);
$this->tester->click(self::$loginButton);
return $this;
}
}
Multi
Session
Testing
http://codeception.com/docs/03-
AcceptanceTests#multi-session-testing
T E S T I N G C O N C U R R E N T
S E S S I O N S
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
Multi Session Testing
$I->amOnPage('/messages');
$david = $I->haveFriend('david');
$david->does(function(AcceptanceTester $I) {
$I->amOnPage('/messages/new');
$I->fillField('body', 'Hello all!');
$I->click('Send');
$I->see('Hello all!', '.message');
});
$I->wait(3);
$I->see('Hello all!', '.message');
$david->leave();
Friends
Mailhog https://github.com/mailhog/MailHog
W E B A P I B A S E D S M T P
T E S T I N G
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
https://github.com/ericmartel/codeception-email-mailhog
Mailhog - Web API based SMTP Testing
"require-dev": {
"ericmartel/codeception-email-mailhog": "^1.0"
}
modules:
enabled:
- MailHog:
url: %CODECEPT_DOMAIN%
port: '8025'
A N D R É W U T T I G
Mailhog - Web API based SMTP Testing
$I->fetchEmails();
$I->accessInboxFor('testuser@example.com');
$I->haveEmails();
$I->haveUnreadEmails();
$I->seeInOpenedEmailSubject('Your Password Reset Link');
$I->seeInOpenedEmailBody('Follow this link to reset your password');
$I->seeInOpenedEmailRecipients('testuser@example.com');
Codeception
Helper https://github.com/portrino/codeception-helper-module
H E L P E R M O D U L E S F O R
T Y P O 3 A N D S H O P W A R E
A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
Codeception TYPO3 Helper
modules:
enabled:
- PortrinoCodeceptionModuleTypo3:
depends: Asserts
domain: www.example.com
$I->executeCommand(Typo3Command::CACHE_FLUSH);
$I->executeSchedulerTask($taskId, $force = false, $environmentVariables = []);
$I->flushCache($force = false, $filesOnly = false);
$I->flushCacheGroups($groups);
$I->importIntoDatabase($file);
Actions
Interfaces / Constants
PortrinoCodeceptionInterfacesDatabaseTablesTypo3Database::FE_USERS
PortrinoCodeceptionInterfacesCookiesTypo3Cookie::FE_USER_COOKIE
PortrinoCodeceptionInterfacesCommandsTypo3Command::CACHE_FLUSH
Codeception TYPO3 Helper
CodeceptionUtilFixtures::add(
'fe_user',
[
'__model' => PortrinoCodeceptionModelTypo3Typo3FrontendUser::class,
'name' => 'andre',
'email' => 'wuttig@mail.com'
]
);
Fixture Models
_boostrap.php
$frontendUser = PortrinoCodeceptionUtilFixtures::get('fe_user');
$I->see($frontendUser->email);
FrontendUserTest.php
MORE
CODECEPTION
MODULES
ANGULARJS, SYMFONY, DOCTRINE ORM,
LARAVEL5, FILE, CLI, YII2, ZF
2 1 • 1 1 • 1 7
DOCTRINE-ORM, SYMFONY, LARAVEL, ZEND FRAMEWORK,
ANGULARJS, CLI, FILE, REDIS
MORE CODECEPTION MODULES
FROM @PORTRINO:
codeception-sitemap-module
(https://github.com/portrino/codeception-sitemap-module)
codeception-yandex-module
(https://github.com/portrino/codeception-yandex-module)
codeception-stripe-module
(https://github.com/portrino/codeception-stripe-module)
codeception-cleverreach-module
(https://github.com/portrino/codeception-cleverreach-module)
TRAVIS
CI
C O N T I N O U S I N T E G R A T I O N
https://travis-ci.org/
2 1 • 1 1 • 1 7
TRAVIS CI
language: php
matrix:
fast_finish: true
include:
- php: 5.5
env: TYPO3_VERSION=^7.6 PHPSTAN=0 COMPAT=1
- php: 5.6
env: TYPO3_VERSION=^7.6 PHPSTAN=0 COMPAT=1
- php: 7.0
env: TYPO3_VERSION=^7.6 PHPSTAN=1 COMPAT=0
- php: 7.1
env: TYPO3_VERSION=^7.6 PHPSTAN=1 COMPAT=0
- php: 7.0
env: TYPO3_VERSION=^8.7 PHPSTAN=1 COMPAT=0
- php: 7.1
env: TYPO3_VERSION=^8.7 PHPSTAN=1 COMPAT=0
sudo: false
travis.yml
TRAVIS CI
travis.yml
before_install:
- mysql -e 'CREATE DATABASE typo3 CHARACTER SET utf8 COLLATE utf8_general_ci;'
- composer self-update
install:
- composer update typo3/cms=$TYPO3_VERSION
before_script:
- export TYPO3_PATH_WEB=$PWD/.build/web
- mkdir -p .build/web/typo3conf
- .build/bin/typo3cms install:setup --non-interactive --database-host-name=127.0.0.1
--database-port=3306 --database-user-name=travis --database-name=typo3 --use-existing-
database --admin-user-name=travis --admin-password=travis123456! --site-setup-
type=site
- .build/bin/typo3cms install:generatepackagestates
- .build/bin/typo3cms database:updateschema *.add,*.change
- .build/bin/typo3cms cache:flushgroups system
- .build/bin/typo3cms configuration:set --path SYS/trustedHostsPattern --value ".*"
- if [[ $COMPAT = 0 ]]; then .build/bin/typo3cms configuration:set --path
SYS/debugExceptionHandler --value
"PortrinoTypo3WhoopsErrorWhoopsExceptionHandler"; fi
TRAVIS CI
travis.yml
script:
- >
echo;
echo "Running PHP PSR-2 coding standard checks (phpcs)";
.build/bin/phpcs --standard=PSR2 --warning-severity=0 src/;
- >
echo;
echo "Running static code analysis (phpstan)";
if [[ $PHPSTAN = 1 ]]; then composer require --dev phpstan/phpstan:^0.8
&& .build/bin/phpstan analyse -l 7 src/Error; fi
- >
echo;
echo "Running tests (codeception)";
.build/bin/codecept run --debug
2 1 • 1 1 • 1 7
@AndreWuttig
@aWuttig
@wuuTANG
THANK
YOU!
ANDRÉ WUTTIG
2 1 • 1 1 • 1 7

More Related Content

What's hot

Using Phing for Fun and Profit
Using Phing for Fun and ProfitUsing Phing for Fun and Profit
Using Phing for Fun and ProfitNicholas Jansma
 
Pulsar Architectural Patterns for CI/CD Automation and Self-Service
Pulsar Architectural Patterns for CI/CD Automation and Self-ServicePulsar Architectural Patterns for CI/CD Automation and Self-Service
Pulsar Architectural Patterns for CI/CD Automation and Self-ServiceDevin Bost
 
Geb for Testing Your Grails Application GR8Conf India 2016
Geb for Testing Your Grails Application  GR8Conf India 2016Geb for Testing Your Grails Application  GR8Conf India 2016
Geb for Testing Your Grails Application GR8Conf India 2016Jacob Aae Mikkelsen
 
PHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return TypesPHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return TypesEric Poe
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type Systemabrummett
 
API Pain Points (PHPNE)
API Pain Points (PHPNE)API Pain Points (PHPNE)
API Pain Points (PHPNE)Phil Sturgeon
 
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Michael Wales
 
Creating own language made easy
Creating own language made easyCreating own language made easy
Creating own language made easyIngvar Stepanyan
 
Web Development with CoffeeScript and Sass
Web Development with CoffeeScript and SassWeb Development with CoffeeScript and Sass
Web Development with CoffeeScript and SassBrian Hogan
 
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHPphp[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHPAdam Englander
 
Service intergration
Service intergration Service intergration
Service intergration 재민 장
 

What's hot (20)

Using Phing for Fun and Profit
Using Phing for Fun and ProfitUsing Phing for Fun and Profit
Using Phing for Fun and Profit
 
Perl6 in-production
Perl6 in-productionPerl6 in-production
Perl6 in-production
 
Php101
Php101Php101
Php101
 
Wsomdp
WsomdpWsomdp
Wsomdp
 
Pulsar Architectural Patterns for CI/CD Automation and Self-Service
Pulsar Architectural Patterns for CI/CD Automation and Self-ServicePulsar Architectural Patterns for CI/CD Automation and Self-Service
Pulsar Architectural Patterns for CI/CD Automation and Self-Service
 
Geb for Testing Your Grails Application GR8Conf India 2016
Geb for Testing Your Grails Application  GR8Conf India 2016Geb for Testing Your Grails Application  GR8Conf India 2016
Geb for Testing Your Grails Application GR8Conf India 2016
 
PHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return TypesPHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return Types
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type System
 
API Pain Points (PHPNE)
API Pain Points (PHPNE)API Pain Points (PHPNE)
API Pain Points (PHPNE)
 
Perl6 grammars
Perl6 grammarsPerl6 grammars
Perl6 grammars
 
Api pain points
Api pain pointsApi pain points
Api pain points
 
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
 
Session8
Session8Session8
Session8
 
SPL, not a bridge too far
SPL, not a bridge too farSPL, not a bridge too far
SPL, not a bridge too far
 
Creating own language made easy
Creating own language made easyCreating own language made easy
Creating own language made easy
 
Web Development with CoffeeScript and Sass
Web Development with CoffeeScript and SassWeb Development with CoffeeScript and Sass
Web Development with CoffeeScript and Sass
 
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHPphp[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
php[world] 2016 - You Don’t Need Node.js - Async Programming in PHP
 
Service intergration
Service intergration Service intergration
Service intergration
 
Session1+2
Session1+2Session1+2
Session1+2
 
Php Rss
Php RssPhp Rss
Php Rss
 

Similar to Testing TYPO3 Applications with Codeception, PHPUnit, Travis-CI

PhpUnit Best Practices
PhpUnit Best PracticesPhpUnit Best Practices
PhpUnit Best PracticesEdorian
 
Keep it simple web development stack
Keep it simple web development stackKeep it simple web development stack
Keep it simple web development stackEric Ahn
 
Controlling Technical Debt with Continuous Delivery
Controlling Technical Debt with Continuous DeliveryControlling Technical Debt with Continuous Delivery
Controlling Technical Debt with Continuous Deliverywalkmod
 
PAC 2020 Santorin - Andreas Grabner
PAC 2020 Santorin - Andreas Grabner PAC 2020 Santorin - Andreas Grabner
PAC 2020 Santorin - Andreas Grabner Neotys
 
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015Sergii Khomenko
 
Puppet Camp London 2015 - Helping Data Teams with Puppet
Puppet Camp London 2015 - Helping Data Teams with PuppetPuppet Camp London 2015 - Helping Data Teams with Puppet
Puppet Camp London 2015 - Helping Data Teams with PuppetPuppet
 
Meteor - not just for rockstars
Meteor - not just for rockstarsMeteor - not just for rockstars
Meteor - not just for rockstarsStephan Hochhaus
 
13 PHPUnit #burningkeyboards
13 PHPUnit #burningkeyboards13 PHPUnit #burningkeyboards
13 PHPUnit #burningkeyboardsDenis Ristic
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionIan Barber
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & ToolsIan Barber
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-pythonEric Ahn
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-pythonEric Ahn
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략Jeen Lee
 
PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!Blanca Mancilla
 
Automate iOS Deployment with Hamper and Schezhen
Automate iOS Deployment with Hamper and SchezhenAutomate iOS Deployment with Hamper and Schezhen
Automate iOS Deployment with Hamper and SchezhenKiran Panesar
 
Zend con 2016 - Asynchronous Prorgamming in PHP
Zend con 2016 - Asynchronous Prorgamming in PHPZend con 2016 - Asynchronous Prorgamming in PHP
Zend con 2016 - Asynchronous Prorgamming in PHPAdam Englander
 
Marko Gargenta_Remixing android
Marko Gargenta_Remixing androidMarko Gargenta_Remixing android
Marko Gargenta_Remixing androidDroidcon Berlin
 
iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기Wanbok Choi
 

Similar to Testing TYPO3 Applications with Codeception, PHPUnit, Travis-CI (20)

Meteor WWNRW Intro
Meteor WWNRW IntroMeteor WWNRW Intro
Meteor WWNRW Intro
 
PhpUnit Best Practices
PhpUnit Best PracticesPhpUnit Best Practices
PhpUnit Best Practices
 
Keep it simple web development stack
Keep it simple web development stackKeep it simple web development stack
Keep it simple web development stack
 
Controlling Technical Debt with Continuous Delivery
Controlling Technical Debt with Continuous DeliveryControlling Technical Debt with Continuous Delivery
Controlling Technical Debt with Continuous Delivery
 
PAC 2020 Santorin - Andreas Grabner
PAC 2020 Santorin - Andreas Grabner PAC 2020 Santorin - Andreas Grabner
PAC 2020 Santorin - Andreas Grabner
 
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
Helping Data Teams with Puppet / Puppet Camp London - Apr 13, 2015
 
Puppet Camp London 2015 - Helping Data Teams with Puppet
Puppet Camp London 2015 - Helping Data Teams with PuppetPuppet Camp London 2015 - Helping Data Teams with Puppet
Puppet Camp London 2015 - Helping Data Teams with Puppet
 
Meteor - not just for rockstars
Meteor - not just for rockstarsMeteor - not just for rockstars
Meteor - not just for rockstars
 
13 PHPUnit #burningkeyboards
13 PHPUnit #burningkeyboards13 PHPUnit #burningkeyboards
13 PHPUnit #burningkeyboards
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & Tools
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-python
 
Py conkr 20150829_docker-python
Py conkr 20150829_docker-pythonPy conkr 20150829_docker-python
Py conkr 20150829_docker-python
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략
 
PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!
 
Automate iOS Deployment with Hamper and Schezhen
Automate iOS Deployment with Hamper and SchezhenAutomate iOS Deployment with Hamper and Schezhen
Automate iOS Deployment with Hamper and Schezhen
 
Zend con 2016 - Asynchronous Prorgamming in PHP
Zend con 2016 - Asynchronous Prorgamming in PHPZend con 2016 - Asynchronous Prorgamming in PHP
Zend con 2016 - Asynchronous Prorgamming in PHP
 
Marko Gargenta_Remixing android
Marko Gargenta_Remixing androidMarko Gargenta_Remixing android
Marko Gargenta_Remixing android
 
iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기
 

Recently uploaded

cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 

Recently uploaded (20)

Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 

Testing TYPO3 Applications with Codeception, PHPUnit, Travis-CI

  • 2. Software Testing PHPUnit, PHPCS, Codeception, PHPMD, PHPStan, PHPLint, PHPCPD, Selenium, ... 2 1 • 1 1 • 1 7 A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N D Y N A M I C T E S T I N G Execution of Code U N I T T E S T S F U N C T I O N A L T E S T S S T A T I C T E S T I N G Static Code Analysis, Review, No Code Execution A C C E P T A N C E T E S T S Functions, Classes, Isolated, No DB! Complete System, DB, Environment, No real FE Browser (UI), API, Technology Independent
  • 3. 1 0 0 0 F U N C T I O N A L T E S T S A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N TESTING TYPO3’S CORE 9 1 0 0 U N I T T E S T S C H R I S T I A N K U H N |   L O L L I 4 2 H T T P S : / / T Y P O 3 . C O M / B L O G / T E S T I N G - T Y P O 3 S - C O R E - P A R T - I - I N F R A S T R U C T U R E / 2 0 0 A C C E P T A N C E T E S T S
  • 4. CODECEPTION E L E G A N T A N D E F F I C I E N T T E S T I N G F O R P H P
  • 5. <?php class FirstCest { public function frontpageWorks(AcceptanceTester $I) { $I->amOnPage('/'); $I->see('Home'); } } L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
  • 6. composer require "codeception/codeception" --dev L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N I N S T A L L A T I O N V I A C O M P O S E R I N S T A L L P H A R G L O B A L L Y sudo curl -LsS http://codeception.com/codecept.phar -o /usr/local/bin/codecept sudo chmod a+x /usr/local/bin/codecept
  • 7. codecept bootstrap L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N S E T U P /tests /acceptance /functional /unit acceptance.suite.yml functional.suite.yml unit.suite.yml codeception.yml
  • 8. codecept bootstrap L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N S E T U P T Y P O 3 E X A M P L E 1 EXT:Example .. /Tests /Acceptance /tests /acceptance /api acceptance.suite.yml api.suite.yml codeception.yml /Functional /Unit .. EXT:Example .. /tests /acceptance /functional /unit acceptance.suite.yml functional.suite.yml unit.suite.yml codeception.yml .. T Y P O 3 E X A M P L E 2 codecept init api codecept init acceptance
  • 9. codeception.yml paths: tests: tests output: tests/_output data: tests/_data support: tests/_support envs: tests/_envs settings: colors: true memory_limit: 1024M actor_suffix: Tester extensions: enabled: - CodeceptionExtensionRunFailed A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N acceptance.suite.yml actor: AcceptanceTester modules: enabled: - PhpBrowser: url: http://localhost:8080/ - HelperAcceptance
  • 10. codeception.yml (2) modules: enabled: - Db: dsn: 'mysql:host=localhost;dbname=%CODECEPT_DB_NAME%;charset=utf8' user: %CODECEPT_DB_USER% password: %CODECEPT_DB_PASSWORD% dump: tests/_data/dump.sql cleanup: true populate: true populator: 'mysql -u $user -p$password $dbname < $dump' reconnect: true - Asserts - PortrinoCodeceptionModuleTypo3 depends: Asserts - REST depends: PhpBrowser url: http://%CODECEPT_DOMAIN%/api/ A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
  • 11. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N G E N E R A T E T E S T S K E L E T O N S codecept generate:cept acceptance First <?php $I = new AcceptanceTester($scenario); $I->wantTo('perform actions and see result');
  • 12. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N G E N E R A T E T E S T S K E L E T O N S codecept generate:cest acceptance First <?php class FirstCest { public function _before(AcceptanceTester $I) { } public function _after(AcceptanceTester $I) { } public function tryToTest(AcceptanceTester $I) { } }
  • 13. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N W R I T E T E S T S <?php class FirstCest { public function frontpageWorks(AcceptanceTester $I) { $I->wantTo('Open TYPO3Camp Website'); $I->amOnUrl('https://www.typo3camp-mitteldeutschland.de/'); $I->seeInTitle('TYPO3Camp Mitteldeutschland'); $I->seeElement('.navbar'); } }
  • 14. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N R U N T E S T S codecept run codecept run --debug codecept run api codecept run acceptance FirstCest:frontpageWorks codecept run tests/acceptance/FirstCest.php::frontpageWorks codecept run -g fast codecept run --env chrome codecept run --xml
  • 15. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N C O D E C E P T I O N S Y N T A X $I->click('Login'); $I->fillField('#input-username', 'John Dough'); $I->pressKey('#input-remarks', 'foo'); A C T I O N S $I->see('Welcome'); $I->seeInTitle('My Company'); $I->seeElement('nav'); $I->dontSeeElement('#error-message'); $this->assertEquals(123, $foo); A S S E R T I O N S
  • 16. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N A C T O R S UnitTester, FunctionalTester, AcceptanceTester Methods are taken from Codeception Modules actor: AcceptanceTester modules: enabled: - PhpBrowser: url: http://localhost/myapp/ - HelperAcceptance acceptance.suite.yml:
  • 17. + high quality + less bugs + better maintainability + easy refactoring + fun P R O L A U R E N H I L L S L I D E 0 1 - high experience - high effort - consequent C O N T R A A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N T E S T D R I V E N D E V E L O P M E N T ?
  • 19. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N P H P U N I T O R C O D E C E P T I O N ? TYPO3 Unit Testing is easier with pure PHPUnit https://github.com/TYPO3/testing-framework https://github.com/Nimut/testing-framework F R A M E W O R K ? W H E R E ? EXT:Foo/Tests/Unit/ EXT:Foo/Tests/Unit/ViewHelpers/RenderViewhelperTest.php EXT:Foo/Tests/Unit/Fixtures/test_data.txt
  • 20. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N class FooViewHelperTest extends NimutTestingFrameworkTestCaseUnitTestCase { protected function setUp() { } protected function tearDown() { } /** * @test */ public function renderNothingWhenNothingToRender() { $this->assertEquals(1,1); } }
  • 21. PROPHECY { "require-dev": { "phpspec/prophecy": "~1.0" } } A N D R É W U T T I G T Y P O 3 U E R G R O U P D R E S D E N https://github.com/phpspec/prophecy
  • 22. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N class FooViewHelperTest extends NimutTestingFrameworkTestCaseUnitTestCase { protected function setUp() { $environementServiceMock = $this->getMockBuilder(EnvironmentService::class)->setMethods( [ 'isEnvironmentInCliMode' ])->getMock(); $environementServiceMock->expects(static::any()) ->method('isEnvironmentInCliMode') ->willReturn(true); GeneralUtility::setSingletonInstance( EnvironmentService::class, $environementServiceMock ); } } PHPUnit MockObjects
  • 23. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N class FooViewHelperTest extends NimutTestingFrameworkTestCaseUnitTestCase { protected function setUp() { $environmentServiceMock = $this->prophesize(EnvironmentService::class); $environmentServiceMock->isEnvironmentInCliMode()->willReturn(false); GeneralUtility::setSingletonInstance( EnvironmentService::class, $environmentService->reveal() ); } Prophecy
  • 24. FUNCTIONAL TESTS D B / A P I / P H P B R O W S E R T E S T I N G
  • 25. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N modules: enabled: - Db: dsn: 'mysql:host=localhost;dbname=%CODECEPT_DB_NAME%;charset=utf8' user: %CODECEPT_DB_USER% password: %CODECEPT_DB_PASSWORD% dump: tests/_data/dump.sql cleanup: true populate: true populator: 'mysql -u $user -p$password $dbname < $dump' #faster ;-) reconnect: true Database - Configuration
  • 26. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N $I->seeInDatabase('fe_users', array('name' => 'Andre', 'email' => 'wuttig@mail.com')); $I->dontSeeInDatabase('fe_users', array('name' => 'Andre', 'email' => 'wuttig@mail.com')); $mail = $I->grabFromDatabase('fe_users', 'email', array('name' => 'Andre')); $I->haveInDatabase('fe_users', array('name' => 'miles', 'email' => 'wuttig@mail.com')); $I->seeNumRecords(1, 'fe_users', ['name' => 'andre']); $I->updateInDatabase('fe_users', ['isAdmin' => true], ['email' => 'miles@davis.com']); Database Testing - Actions / Assertions / Grabbers
  • 27. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N #!/bin/bash PASSWORD=$CODECEPT_DB_PASSWORD HOST=$CODECEPT_DB_HOST USER=$CODECEPT_DB_USER DATABASE=$CODECEPT_DB_NAME DB_FILE=dump.sql EXCLUDED_TABLES=( be_sessions cf_cache_hash sys_log ... ) ... Database Testing - Creating Testdata https://gist.github.com/aWuttig/58599ae722a5a993172b39046ca07d0a dump.sh
  • 28. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N modules: enabled: - REST: depends: PhpBrowser url: 'http://serviceapp/api/v1/' REST API - Configuration
  • 29. L A U R E N H I L L S L I D E 0 6A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N $I->amHttpAuthenticated('jon_snow', 'targaryen'); $I->haveHttpHeader('X-Requested-With', 'Codeception'); $I->sendGET('user'); $I->sendPOST('/user', 'name' => 'andre')); $I->sendPUT('/user', array('id' => 123, 'name' => 'andré')); $I->sendDELETE('/user/123'); REST API - Actions / Assertions / Grabbers $I->seeResponseCodeIs(200); $I->seeResponseContains('foo'); $I->seeHttpHeaderOnce('Cache-Control'); $I->seeResponseContainsJson(array('name' => 'john')); $I->seeResponseJsonMatchesJsonPath('$.data.0.name'); $I->seeResponseMatchesJsonType(['user_id' => 'integer','is_active' => 'boolean']);
  • 30. Phiremock https://github.com/mcustiel/phiremock M O C K H T T P R E Q U E S T A N D R E S T A P I ´ S A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
  • 33. ACCEPTANCE TESTING W E B D R I V E R , R E A L B R O W S E R
  • 34. Selenium Driver + Chrome nohup bash -c "java -jar selenium-server-standalone.jar &" && sleep 1; cat nohup.out - ls -al export DISPLAY=:99.0 sh -e /etc/init.d/xvfb start sleep 3 # give xvfb some time to start - ls -al X Window Virtual Framebuffer wget -c -nc --retry-connrefused --tries=0 https://goo.gl/s4o9Vx -O selenium-server-standalone.jar Selenium Server Standalone wget -c -nc --retry-connrefused --tries=0 http://chromedriver.storage.googleapis.com/2.31/chromedriver_linux64.zip unzip -o -q chromedriver_linux64.zip Chrome Driver Start Selenium Server
  • 35. Webdriver - Configuration modules: enabled: - WebDriver: url: http://%CODECEPT_DOMAIN% host: localhost browser: chrome restart: true capabilities: chromeOptions: args: ["--headless", "--disable-gpu"] binary: "/usr/bin/google-chrome" codeception.yml
  • 36. Webdriver - Action / Assertions $I->click('Submit'); $I->closeTab(); $I->seeElement('.error'); $I->waitForElement('#agree_button', 30); // secs $I->waitForText('foo', 30); $I->switchToIFrame("another_frame"); $I->setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3'); $I->selectOption('form select[name=account]', 'Premium'); $I->resizeWindow(800, 600); $I->scrollTo(['css' => '.checkout'], 20, 50); $I->pressKey('#page','a'); $I->makeScreenshot('edit_page'); $myVar = $I->executeJS('return $("#myField").val()');
  • 38. Page Object Pattern namespace Page; class LoginPage { public static $URL = '/login'; public static $usernameField = '#mainForm #username'; public static $passwordField = '#mainForm input[name=password]'; public static $loginButton = '#mainForm input[type=submit]'; public function login($username, $password) { $this->tester->fillField(self::$usernameField, $username); $this->tester->fillField(self::$passwordField, $password); $this->tester->click(self::$loginButton); return $this; } }
  • 39. Page Object Pattern class LoginCest { public function loginAsUser(AcceptanceTester $I, LoginPage $loginPage) { $loginPage->open()->login('wuttig','123456'); $I->seeElement('#userprofile'); } }
  • 40. Webdriver - Action / Assertions 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]'; public function login($username, $password) { $this->tester->fillField(self::$usernameField, $username); $this->tester->fillField(self::$passwordField, $password); $this->tester->click(self::$loginButton); return $this; } }
  • 41. Multi Session Testing http://codeception.com/docs/03- AcceptanceTests#multi-session-testing T E S T I N G C O N C U R R E N T S E S S I O N S A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
  • 42. Multi Session Testing $I->amOnPage('/messages'); $david = $I->haveFriend('david'); $david->does(function(AcceptanceTester $I) { $I->amOnPage('/messages/new'); $I->fillField('body', 'Hello all!'); $I->click('Send'); $I->see('Hello all!', '.message'); }); $I->wait(3); $I->see('Hello all!', '.message'); $david->leave(); Friends
  • 43. Mailhog https://github.com/mailhog/MailHog W E B A P I B A S E D S M T P T E S T I N G A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N https://github.com/ericmartel/codeception-email-mailhog
  • 44. Mailhog - Web API based SMTP Testing "require-dev": { "ericmartel/codeception-email-mailhog": "^1.0" } modules: enabled: - MailHog: url: %CODECEPT_DOMAIN% port: '8025' A N D R É W U T T I G
  • 45. Mailhog - Web API based SMTP Testing $I->fetchEmails(); $I->accessInboxFor('testuser@example.com'); $I->haveEmails(); $I->haveUnreadEmails(); $I->seeInOpenedEmailSubject('Your Password Reset Link'); $I->seeInOpenedEmailBody('Follow this link to reset your password'); $I->seeInOpenedEmailRecipients('testuser@example.com');
  • 46. Codeception Helper https://github.com/portrino/codeception-helper-module H E L P E R M O D U L E S F O R T Y P O 3 A N D S H O P W A R E A N D R É W U T T I G T Y P O 3 U S E R G R O U P D R E S D E N
  • 47. Codeception TYPO3 Helper modules: enabled: - PortrinoCodeceptionModuleTypo3: depends: Asserts domain: www.example.com $I->executeCommand(Typo3Command::CACHE_FLUSH); $I->executeSchedulerTask($taskId, $force = false, $environmentVariables = []); $I->flushCache($force = false, $filesOnly = false); $I->flushCacheGroups($groups); $I->importIntoDatabase($file); Actions Interfaces / Constants PortrinoCodeceptionInterfacesDatabaseTablesTypo3Database::FE_USERS PortrinoCodeceptionInterfacesCookiesTypo3Cookie::FE_USER_COOKIE PortrinoCodeceptionInterfacesCommandsTypo3Command::CACHE_FLUSH
  • 48. Codeception TYPO3 Helper CodeceptionUtilFixtures::add( 'fe_user', [ '__model' => PortrinoCodeceptionModelTypo3Typo3FrontendUser::class, 'name' => 'andre', 'email' => 'wuttig@mail.com' ] ); Fixture Models _boostrap.php $frontendUser = PortrinoCodeceptionUtilFixtures::get('fe_user'); $I->see($frontendUser->email); FrontendUserTest.php
  • 49. MORE CODECEPTION MODULES ANGULARJS, SYMFONY, DOCTRINE ORM, LARAVEL5, FILE, CLI, YII2, ZF 2 1 • 1 1 • 1 7
  • 50. DOCTRINE-ORM, SYMFONY, LARAVEL, ZEND FRAMEWORK, ANGULARJS, CLI, FILE, REDIS MORE CODECEPTION MODULES FROM @PORTRINO: codeception-sitemap-module (https://github.com/portrino/codeception-sitemap-module) codeception-yandex-module (https://github.com/portrino/codeception-yandex-module) codeception-stripe-module (https://github.com/portrino/codeception-stripe-module) codeception-cleverreach-module (https://github.com/portrino/codeception-cleverreach-module)
  • 51. TRAVIS CI C O N T I N O U S I N T E G R A T I O N https://travis-ci.org/ 2 1 • 1 1 • 1 7
  • 52. TRAVIS CI language: php matrix: fast_finish: true include: - php: 5.5 env: TYPO3_VERSION=^7.6 PHPSTAN=0 COMPAT=1 - php: 5.6 env: TYPO3_VERSION=^7.6 PHPSTAN=0 COMPAT=1 - php: 7.0 env: TYPO3_VERSION=^7.6 PHPSTAN=1 COMPAT=0 - php: 7.1 env: TYPO3_VERSION=^7.6 PHPSTAN=1 COMPAT=0 - php: 7.0 env: TYPO3_VERSION=^8.7 PHPSTAN=1 COMPAT=0 - php: 7.1 env: TYPO3_VERSION=^8.7 PHPSTAN=1 COMPAT=0 sudo: false travis.yml
  • 53. TRAVIS CI travis.yml before_install: - mysql -e 'CREATE DATABASE typo3 CHARACTER SET utf8 COLLATE utf8_general_ci;' - composer self-update install: - composer update typo3/cms=$TYPO3_VERSION before_script: - export TYPO3_PATH_WEB=$PWD/.build/web - mkdir -p .build/web/typo3conf - .build/bin/typo3cms install:setup --non-interactive --database-host-name=127.0.0.1 --database-port=3306 --database-user-name=travis --database-name=typo3 --use-existing- database --admin-user-name=travis --admin-password=travis123456! --site-setup- type=site - .build/bin/typo3cms install:generatepackagestates - .build/bin/typo3cms database:updateschema *.add,*.change - .build/bin/typo3cms cache:flushgroups system - .build/bin/typo3cms configuration:set --path SYS/trustedHostsPattern --value ".*" - if [[ $COMPAT = 0 ]]; then .build/bin/typo3cms configuration:set --path SYS/debugExceptionHandler --value "PortrinoTypo3WhoopsErrorWhoopsExceptionHandler"; fi
  • 54. TRAVIS CI travis.yml script: - > echo; echo "Running PHP PSR-2 coding standard checks (phpcs)"; .build/bin/phpcs --standard=PSR2 --warning-severity=0 src/; - > echo; echo "Running static code analysis (phpstan)"; if [[ $PHPSTAN = 1 ]]; then composer require --dev phpstan/phpstan:^0.8 && .build/bin/phpstan analyse -l 7 src/Error; fi - > echo; echo "Running tests (codeception)"; .build/bin/codecept run --debug
  • 55. 2 1 • 1 1 • 1 7 @AndreWuttig @aWuttig @wuuTANG
  • 56. THANK YOU! ANDRÉ WUTTIG 2 1 • 1 1 • 1 7