symfony (unit, functional) testing

37
Symfony Testing Basel Issmail [email protected]

Upload: basel-issmail

Post on 23-Jan-2018

40 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Symfony (Unit, Functional) Testing

Symfony Testing

Basel [email protected]

Page 2: Symfony (Unit, Functional) Testing
Page 3: Symfony (Unit, Functional) Testing

Why Testing?Prevent Bugs. (Reputation)

Prevent Fixing same Bugs more than once. (add additional cases each time)

Faster than manual testing.

Additional Documentation.

Upgrading your platform? Refactoring your Code? NO PROBLEM

Keeping your code quality.. Spaghetti Code is not testable ;)

Making QA jobless

Page 4: Symfony (Unit, Functional) Testing

1- Unit TestingUnit tests are used to test your “business logic”

Page 5: Symfony (Unit, Functional) Testing

If you want the design

of your code to be

better ... write Unit Tests

“Symfony Live London 2015 - Ciaran McNulty”

Page 6: Symfony (Unit, Functional) Testing

Most Used Assertions

AssertTrue/AssertFalseAssertEquals(AssertGreaterThan, LessThan)(GreaterThanOrEqual, LessThanOrEqual) AssertContainsAssertTypeAssertNullAssertFileExistsAssertRegExp

Page 7: Symfony (Unit, Functional) Testing

<?php

namespace TDD;

class Receipt {

public function total(array $items = []) {

return array_sum($items);

}

}

Page 8: Symfony (Unit, Functional) Testing

<?php

namespace TDD\Test;

use PHPUnit\Framework\TestCase;

use TDD\Receipt;

class ReceiptTest extends TestCase {

public function testTotal() {

$Receipt = new Receipt();

$this->assertEquals(

14,

$Receipt->total([0,2,5,8]),

'When summing the total should equal 15'

);

}

}

Page 9: Symfony (Unit, Functional) Testing
Page 10: Symfony (Unit, Functional) Testing

PHPUnit outcomes.

Printed when the test succeeds.

F

Printed when an assertion fails while running the test method.

E

Printed when an error occurs while running the test method.

S

Printed when the test has been skipped.

I

Printed when the test is marked as being incomplete or not yet implemented

Page 11: Symfony (Unit, Functional) Testing

PhpUnit Command linePhpunit

--filter=

--testsuite= <name,...>

--coverage-html <dir>

Other configurations are imported from phpunit.xml (next slide)

#

Page 12: Symfony (Unit, Functional) Testing

<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="app/autoload.php" backupGlobals="false" colors="true" verbose="true"

stopOnFailure="false">

<php>

<server name="KERNEL_DIR" value="/app/" />

<env name="SYMFONY_DEPRECATIONS_HELPER" value="weak" />

</php>

<testsuites>

<!-- compose tests into test suites -->

<testsuite name="Project Test Suite">

<!-- You can either choose directory or single files -->

<directory>tests</directory>

<file>tests/General/ApplicationAvailabilityFunctionalTest.php</file>

</testsuite>

</testsuites>

Page 13: Symfony (Unit, Functional) Testing

<!--- This part is for code coverage (choose which directory to check and which to execlude from

coverage)-->

<filter>

<whitelist processUncoveredFilesFromWhitelist="true">

<directory suffix=".php">./src/AcmeBundle/Repository</directory>

<exclude>

<directory suffix=".php">./src/AcmeBundle/Tests</directory>

</exclude>

</whitelist>

</filter>

</phpunit>

Page 14: Symfony (Unit, Functional) Testing

Arrange-Act-Assert

Page 15: Symfony (Unit, Functional) Testing

General Principles

Test In Isolation

Test on thing per Function

If hard to test, reimplement your code

Page 16: Symfony (Unit, Functional) Testing

class ReceiptTest extends TestCase {

public function setUp() {

$this->Receipt = new Receipt();

}

public function tearDown() {

unset($this->Receipt);

}

public function testTotal() {

//arrange

$input = [0,2,5,8];

//ACT

$output = $this->Receipt->total($input);

//Assert

$this->assertEquals(

15,

$output,

'When summing the total should equal 15');

}}

Page 17: Symfony (Unit, Functional) Testing

//Test Function

public function testTax() {

$inputAmount = 10.00;

$taxInput = 0.10;

$output = $this->Receipt->tax($inputAmount, $taxInput);

$this->assertEquals(

1.00,

$output,

'The tax calculation should equal 1.00'

);

}

//Actual Function

public function tax($amount, $tax) {

return ($amount * $tax);

}

Page 18: Symfony (Unit, Functional) Testing

Data Providers/**

* @dataProvider provideTotal

*/

public function testTotal($items, $expected) {

$coupon = null;

$output = $this->Receipt->total($items, $coupon);

$this->assertEquals(

$expected,

$output,

"When summing the total should equal {$expected}"

);

}

public function provideTotal() {

return [

[[1,2,5,8], 16],

[[-1,2,5,8], 14],

[[1,2,8], 11],

];

}

Page 19: Symfony (Unit, Functional) Testing

Test DoublesReplace Dependency (Isolation)

Ensure a condition occurs

Improve the performance of our tests

Dummy

Fake

Stub

Spy

Mock

Page 20: Symfony (Unit, Functional) Testing

Dummy

● Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

Eg: empty $config array

Page 21: Symfony (Unit, Functional) Testing

Fake

● Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production.

Eg: in memory database

Page 22: Symfony (Unit, Functional) Testing

Stub

● Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.

Eg: stub for isConnected() which returns false.

Page 23: Symfony (Unit, Functional) Testing

Spy

● Spies are stubs that also record some information based on how they were called.

Eg: an email service that records how many messages it was sent.

Page 24: Symfony (Unit, Functional) Testing

Mock

● Mocks objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Page 25: Symfony (Unit, Functional) Testing

public function total(array $items = [], $coupon) {

$sum = array_sum($items);

if (!is_null($coupon)) {

return $sum - ($sum * $coupon);

}

return $sum;

}

Page 26: Symfony (Unit, Functional) Testing

public function testTotal() {

$input = [0,2,5,8];

$coupon = null;

$output = $this->Receipt->total($input, $coupon);

$this->assertEquals(

15,

$output,

'When summing the total should equal 15'

);

}

public function testTotalAndCoupon() {

$input = [0,2,5,8];

$coupon = 0.20;

$output = $this->Receipt->total($input, $coupon);

$this->assertEquals(

12,

$output,

'When summing the total should equal 12'

);

}

Dummy

Page 27: Symfony (Unit, Functional) Testing

public function total(array $items = [], $coupon) {

$sum = array_sum($items);

if (!is_null($coupon)) {

return $sum - ($sum * $coupon);

}

return $sum;

}

public function tax($amount, $tax) {

return ($amount * $tax);

}

public function postTaxTotal($items, $tax, $coupon) {

$subtotal = $this->total($items, $coupon); //total -> 10

$subtotal += $tax;

return $subtotal + $this->tax($subtotal, $tax); //tax -> 1

}

Page 28: Symfony (Unit, Functional) Testing

public function testPostTaxTotal() {

$Receipt = $this->getMockBuilder('TDD\Receipt')

->setMethods(['tax', 'total'])

->getMock();

$Receipt->method('total')

->will($this->returnValue(10.00));

$Receipt->method('tax')

->will($this->returnValue(1.00));

$result = $Receipt->postTaxTotal([1,2,5,8], 0.20, null);

$this->assertEquals(11.00, $result);

}

Stub

Page 29: Symfony (Unit, Functional) Testing

public function testPostTaxTotal () {

$items = [1,2,5,8];

$tax = 0.20;

$coupon = null;

$Receipt = $this->getMockBuilder('TDD\Receipt')

->setMethods(['tax', 'total'])

->getMock();

$Receipt->expects($this->once())

->method('total')

->with($items, $coupon)

->will($this->returnValue(10.00));

$Receipt->expects($this->once())

->method('tax')

->with(10.00, $tax)

->will($this->returnValue(1.00));

$result = $Receipt->postTaxTotal([1,2,5,8], 0.20, null);

$this->assertEquals(11.00, $result);

}

Mock

Page 30: Symfony (Unit, Functional) Testing

TDDWrite Test, Run Test, Write Code, Run Test, Repeat Until Completed

Page 31: Symfony (Unit, Functional) Testing

Data Fixturesphp bin/console doctrine:fixtures:load

class LoadJobsData extends AbstractFixture implements OrderedFixtureInterface

{

public function load(ObjectManager $manager)

{

$user = $manager->getRepository('UserBundle:User')->findBy(array('username' => 'friik'));

$organization = $manager->getRepository('JobsBundle:Organization')->findBy(array('name' =>

'friikcom'));

Page 32: Symfony (Unit, Functional) Testing

$job = new Job();

$job->setCreatedBy($user[0]);

$job->setCreatedAt();

$job->setStartDate(new \DateTime());

$job->setEndDate(new \DateTime('+1 week'));

$job->setActive(1);

$job->setJobCaption('new job for all interested');

$job->setEmplType(2);

$job->setOrganization($organization[0]);

$manager->persist($job);

$manager->flush();

}

public function getOrder()

{

return 4;

}

}

Page 33: Symfony (Unit, Functional) Testing

protected function setUp()

{

self::bootKernel();

$this->em = static::$kernel->getContainer()

->get('doctrine')

->getManager();}

public function testFindAllJobsOrderedByDateReturnsResults()

{

$expectedOutput = 2;

$job = $this->em

->getRepository('JobsBundle:Job')

->findAllJobsOrderedByDate()->getResult(Query::HYDRATE_ARRAY);

$this->assertCount($expectedOutput, $job);

}

protected function tearDown()

{

parent::tearDown();

$this->em->close();

$this->em = null; // avoid memory leaks

}

}

Page 34: Symfony (Unit, Functional) Testing

2- Functional Testingcheck the integration of the different layers of an

application

Page 35: Symfony (Unit, Functional) Testing

Define a client then Request/**

* @dataProvider urlProvider

*/

public function testPageIsSuccessful($url)

{

$client = self::createClient();

$client->request('GET', $url);

$this->assertTrue($client->getResponse()->isSuccessful());

}

public function urlProvider()

{

return array(

array('/jobs'),

array('/jobs/organization/show'),

array('/jobs/organization/add'),

array('/jobs/organization/check'),

);

Page 36: Symfony (Unit, Functional) Testing

public function testIndexPageRequestAuthorized()

{

$client = static::createClient();

$crawler = $client->request('GET', '/jobs/job', array(), array(), array(

'PHP_AUTH_USER' => 'friik',

'PHP_AUTH_PW' => 'friikfriik',

));

$crawler = $client->followRedirect();

$response = $client->getResponse();

$this->assertEquals(200, $response->getStatusCode());

}

Authorized client

Page 37: Symfony (Unit, Functional) Testing

public function testOrganizationShowExampleTests()

{

$client = static::createClient();

$crawler = $client->request('GET', '/jobs/organization/show');

$response = $client->getResponse();

//Status Code

// $this->assertEquals(200, $response->getStatusCode());

//Check if page contains content

//$this->assertContains('company', $response->getContent());

$img = $crawler->filterXPath('//img');

$atr = $img->attr('src');

//check for alt attr in image tags

$crawler->filter('img')->each(function ($node, $i) {

$alt = $node->attr('alt');

$this->assertNotNull($alt);

});

}