Testing your application
by Joeri Timmermans

- 28 years old
- Gamer, PHP Developer
with a passion for Food & Drinks - Interactive Multimedia Design
- Symfony2 @
- @Joeri_timmer
- /pix-art
- www.pix-art.be (Blog)




Who am i?

- What is "Testing"?
- Debunking the myths
- Why do Testing?
- Different types of Testing
- PHPUnit & Behat
- Starting with PHPUnit
- Basic assertions
- Hello world!
- Fixtures
- Mock objects
- Starting with Behat
- Mink Extension
- Page visiting
- Interesting reads
- Questions?
// TODO:


What is "Testing"?
Wikipedia:
"Software testing is an investigation conducted to provide stakeholders with information about the quality of the product or service under test."

Debunking the myths
- It takes too long
- There’s no need to test:
my code already works! - Expensive
- It’s no fun

- Automation
- Readable code == Testable code
- Test code on functionality
- Reduce bugs in new and existing features
- Reduce cost of changes
- Easier refactoring
- Progress indication of the project
- Alerts generation for CI-tools
- Forces you to slow down and think
- Speed up development and reduce fear
Why do Testing?

Different types of Testing

Unit
System
Integration
Functional
User Acceptance
Performance/Stress
Usability
White Box/ Black Box
Security/ Penetration
PHPUnit
- Unit Testing
- Created by Sebastian Bergmann
- Part of xUnit Family
- /sebastianbergmann/phpunit

Behat
- Feature/Integration Testing
- Created by Konstantin Kudryashov
- Behavior-driven development framework
- /Behat/Behat



- Download phar:
https://phpunit.de - Composer:
"phpunit/phpunit": "4.3.*",
- Setup phpunit.xml
Starting with PHPUnit

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals = "false" backupStaticAttributes = "false"
colors = "true" convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true" convertWarningsToExceptions = "true"
processIsolation = "false" stopOnFailure = "false"
syntaxCheck = "false" bootstrap = "bootstrap.php.cache" >
<testsuites>
<testsuite name="Project Test Suite">
<directory>../src/*/*Bundle/Tests</directory>
<directory>../src/*/Bundle/*Bundle/Tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>../src</directory>
<exclude>
<directory>../src/*/*Bundle/Resources</directory>
<directory>../src/*/*Bundle/Tests</directory>
<directory>../src/*/Bundle/*Bundle/Resources</directory>
<directory>../src/*/Bundle/*Bundle/Tests</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
Basic assertions
-
AssertTrue/AssertFalse - Check the input to verify it equals true/false
-
AssertEquals - Check the result against another input for a match
-
AssertGreaterThan - Check the result to see if it’s larger than a value
(there’s also LessThan, GreaterThanOrEqual, and LessThanOrEqual) -
AssertContains - Check that the input contains a certain value
-
AssertType - Check that a variable is of a certain type
-
AssertNull - Check that a variable is null
-
AssertRegExp - Check the input against a regular expression
-
...

Hello world!
<?php
namespace Example;
class HelloWorld
{
public $helloWorld;
public function __construct($string = 'Hello World!')
{
$this->helloWorld = $string;
}
public function sayHello()
{
return $this->helloWorld;
}
}

Our first test
<?php
namespace Example;
class HelloWorldTest extends \PHPUnit_Framework_TestCase
{
public function testSayHello()
{
$hw = new HelloWorld();
$string = $hw->sayHello();
$this->assertEquals('Hello World!', $string);
}
}

The result!
PHPUnit 4.2.5 by Sebastian Bergmann.
Configuration read from /var/www/example/build/phpunit.xml
.
Time: 70 ms, Memory: 3.50Mb
OK (1 test, 1 assertion)

Fixtures

-
"Known state" of an application
- needs to be "set up" at start
- needs to be "torn down" at end
- shares "states" over test methods
<?php
namespace Example;
class MyListTest extends \PHPUnit_Framework_TestCase
{
protected $myList;
public function setUp()
{
$this->myList = array();
}
public function testMyListEmpty()
{
$this->assertEquals(0, sizeof($this->myList));
}
public function testMyListHasOne()
{
array_push($this->myList, 'myItem');
$this->assertEquals(1, sizeof($this->myList));
}
public function tearDown()
{
unset($this->myList);
}
}
The result!
PHPUnit 4.2.5 by Sebastian Bergmann.
Configuration read from /var/www/example/build/phpunit.xml
..
Time: 67 ms, Memory: 3.50Mb
OK (2 tests, 2 assertions)

Mock objects
- Simulated objects
- Mimics API or behaviour
- In a controlled way
- To test real objects

Mock objects
<?php
namespace Example;
class HelloMailer
{
public $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function sendMessage($message)
{
return $this->mailer->send($message);
}
}

<?php
namespace Example;
class HelloMailerTest extends \PHPUnit_Framework_TestCase
{
protected $mailer;
public function setUp()
{
$mailer = $this->getMockBuilder('Example\Mailer')
->setMockClassName('Mailer')
->disableOriginalConstructor()
->setMethods(array('send'))
->getMock();
$mailer->expects($this->any())
->method('send')
->with($this->equalTo('Hello mailer!'))
->will($this->returnValue(true));
$this->mailer = $mailer;
}
public function testSend()
{
$hm = new HelloMailer($this->mailer);
$response = $hm->sendMessage('Hello mailer!');
$this->assertTrue($response);
}
}
The result!
PHPUnit 4.2.5 by Sebastian Bergmann.
Configuration read from /var/www/example/build/phpunit.xml
.
Time: 80 ms, Memory: 4.00Mb
OK (1 test, 1 assertion)


- Composer:
"behat/behat": "^3.0", "behat/mink": "^1.6", "behat/mink-extension": "^2.0", "behat/mink-selenium2-driver": "1.2.0"
- Setup behat.yml
- FeatureContext.php
Starting with Behat

behat.yml
default:
suites:
functional:
paths: [ %paths.base%/features ]
contexts:
- FeatureContext
extensions:
Behat\MinkExtension:
base_url: http://localhost/
sessions:
default:
selenium2: ~

FeatureContext.php
<?php
use Behat\MinkExtension\Context\MinkContext;
/**
* Features context.
*/
class FeatureContext extends MinkContext
{
/**
* Initializes context.
* Every scenario gets its own context object.
*/
public function __construct()
{
// Initialize your context here
}
/**
* @Given /^I wait for (\d+) seconds$/
*/
public function iWaitForSeconds($seconds)
{
$this->getSession()->wait($seconds * 1000);
}
}
Mink Extension

More info : https://github.com/Behat/MinkExtension

Our first test
#pagevisit.feature
Feature: pagevisit
This is a standard behat test to see if the given
page is visited and show the right content
Scenario: When i visit the homepage i should see notifications
Given I am on "/interactive-multimedia-design-imd"
Then I should see "Interactive multimedia design (IMD)"
Then I should see "Professionele Bachelor"


The result!
$ vendor/bin/behat
Feature: pagevisit
This is a standard behat test to see if the
given page is visited and show the right content
Scenario: When i visit the homepage i should see notifications
# features/pagevisit.feature:4
Given I am on "/interactive-multimedia-design-imd"
# FeatureContext::visit()
Then I should see "Interactive multimedia design (IMD)"
# FeatureContext::assertPageContainsText()
Then I should see "Professionele Bachelor"
# FeatureContext::assertPageContainsText()
1 scenario (1 passed)
3 steps (3 passed)
0m7.77s (13.74Mb)

- https://phpunit.de/
- http://www.dragonbe.com/
- http://www.sitepoint.com/tutorial-introduction-to-unit-testing-in-php-with-phpunit/
- http://www.pix-art.be/post/testing-your-symfony-application-with-behat

Interesting reads
Questions?

- (www.intracto.com)
- @Joeri_timmer
- /pix-art
- www.pix-art.be (Blog)




Thank you!
https://github.com/pix-art/phpunitdemo

Try it yourself
Testing your application
By Joeri Timmermans
Testing your application
Introduction to Automated Testing with PHPUnit and Behat.
- 1,440