symfony (unit, functional) testing

Post on 23-Jan-2018

42 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Symfony Testing

Basel Issmailbasel.issmail@gmail.com

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

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

If you want the design

of your code to be

better ... write Unit Tests

“Symfony Live London 2015 - Ciaran McNulty”

Most Used Assertions

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

<?php

namespace TDD;

class Receipt {

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

return array_sum($items);

}

}

<?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'

);

}

}

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

PhpUnit Command linePhpunit

--filter=

--testsuite= <name,...>

--coverage-html <dir>

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

#

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

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

Arrange-Act-Assert

General Principles

Test In Isolation

Test on thing per Function

If hard to test, reimplement your code

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');

}}

//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);

}

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],

];

}

Test DoublesReplace Dependency (Isolation)

Ensure a condition occurs

Improve the performance of our tests

Dummy

Fake

Stub

Spy

Mock

Dummy

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

Eg: empty $config array

Fake

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

Eg: in memory database

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.

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.

Mock

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

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

$sum = array_sum($items);

if (!is_null($coupon)) {

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

}

return $sum;

}

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

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

}

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

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

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

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'));

$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;

}

}

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

}

}

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

application

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'),

);

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

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);

});

}

top related