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

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 (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

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 

Recently uploaded (20)

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 

Testing TYPO3 Applications

  • 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