unit and functional testing in symfony introduction to...

22
Unit and Functional Testing in Symfony Unit and Functional Testing in Symfony / / Introduction to Reflection Introduction to Reflection Shawn Biddle(shawncplus) PHP Dev, STUDIO, llc http://www.whoisstudio.com

Upload: others

Post on 18-Oct-2020

34 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Unit and Functional Testing in SymfonyUnit and Functional Testing in Symfony//

Introduction to ReflectionIntroduction to Reflection

Shawn Biddle(shawncplus)PHP Dev, STUDIO, llc

http://www.whoisstudio.com

Page 2: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

DO THEM!!1one!

Unit TestsUnit Tests

Page 3: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

What Unit Tests Are ForWhat Unit Tests Are For

Revision 1: Author: shawnbfunction hello(){ return 'world';}

Revision 2: Author: jonrfunction hello(WorldStringClass $world){ return $world->name;}

shawnb was smart and wrote a unit test when he created the hello() function.

$test->is(hello(), 'world', 'hello() returns ”world”'); // PASS

jonr commits his change without running the unit test then shawnb updates and runs his test and it fails. Now shawnb can make jonr wear the dunce hat for the day because he broke the function.

$test->is(hello(), 'world', 'hello() returns ”world”'); // FAIL

Page 4: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

What Unit Tests Are NOT ForWhat Unit Tests Are NOT For

➔ Unit tests are NOT human QA➔ Unit tests are NOT functional QA➔ Unit tests are NOT a replacement for communication

Unit tests are not an end-all replacement for someone looking over your code. They do not test implementations of objects/functions. They definitely do not remove the need for communication with other developers.

Page 5: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Unit Tests in SymfonyUnit Tests in Symfony

<?php include(dirname(__FILE__).'/../bootstrap/unit.php');require_once(dirname(__FILE__).'/../../lib/strtolower.php'); $t = new lime_test(7, new lime_output_color()); // strtolower()$t->diag('strtolower()');$t->isa_ok(strtolower('Foo'), 'string', 'strtolower() returns a string');$t->is(strtolower('FOO'), 'foo', 'strtolower() transforms the input to lowercase');$t->is(strtolower('foo'), 'foo', 'strtolower() leaves lowercase characters unchanged');$t->is(strtolower('12#?@~'), '12#?@~', 'strtolower() leaves non alphabetical characters unchanged');$t->is(strtolower('FOO BAR'), 'foo bar', 'strtolower() leaves blanks alone');$t->is(strtolower('FoO bAr'), 'foo bar', 'strtolower() deals with mixed case input');$t->is(strtolower(''), 'foo', 'strtolower() transforms empty strings into foo');

Page 6: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Unit Testing FunctionsUnit Testing Functions

Page 7: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Testing With FixturesTesting With Fixtures

<?php include(dirname(__FILE__).'/../bootstrap/unit.php'); require_once($sf_symfony_lib_dir.'/yaml/sfYaml.class.php');

$testCases = sfYaml::load(dirname(__FILE__).'/fixtures.yml'); $t = new lime_test(count($testCases), new lime_output_color());

// isPathAbsolute() $t->diag('isPathAbsolute()'); foreach ($testCases as $case) { $t->is(sfToolkit::isPathAbsolute($case['input']), $case['output'],$case['comment']); }

- input: '/test' output: true comment: isPathAbsolute() returns true if path is absolute- input: 'test' output: false comment: isPathAbsolute() returns false if path is relative

Page 8: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Works the same in Doctrine and Propel(really)

Accessing the DatabaseAccessing the Database

include(dirname(__FILE__).'/../bootstrap/unit.php');new sfDatabaseManager(ProjectConfiguration::getApplicationConfiguration('public', 'home', true));

Page 9: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

// Test directory structuretest/ unit/ myFunctionTest.php mySecondFunctionTest.php foo/ barTest.php

> ./symfony test:unit myFunction ## Run myFunctionTest.php> ./symfony test:unit myFunction mySecondFunction ## Run both tests> ./symfony test:unit 'foo/*' ## Run barTest.php> ./symfony test:unit '*' ## Run all tests (recursive)

Putting It TogetherPutting It Together

Page 10: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

DO THEM!!1one!

Functional TestsFunctional Tests

Page 11: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

What Functional Tests Are ForWhat Functional Tests Are For

Short AnswerFunctional tests validate parts of your applications.

Long AnswerThey simulate a browsing session, make requests, and check elements in the response, just like you would do manually to

validate that an action does what it's supposed to do. In functional tests, you run a scenario corresponding to a use case.

Page 12: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

What Functional Tests Are NOT ForWhat Functional Tests Are NOT For

● Functional tests are NOT human QA● Functional tests are NOT functional QA● Functional tests are NOT a replacement for communication

Functional tests are not an end-all replacement for someone looking over your code. They definitely do not remove the need for communication with other developers.

Page 13: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Functional Tests in SymfonyFunctional Tests in Symfony

Page 14: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

sfTestBrowser FunctionssfTestBrowser Functions

getAndCheck($module, $action, Retrieves and checks an action $url = null, $code = 200)throwsException($class = null,

$message = null) Tests if an exception is thrown by the latest request

isResponseHeader($key, $value) Tests for a response header.

isStatusCode($statusCode = 200) Tests a status code for the current browser

call($uri, $mothod = "get", Call a request $parameters = array(), $changeStack = true)

isRedirected($boolean = true) Tests if current request has been redirected

...

See http://www.symfony-project.org/api/1_1/sfTestBrowser for the full list.

Page 15: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

checkResponseElementcheckResponseElement

The behavior of the checkResponseElement() method depends on the type of the second argument that it receives:

➔ If it is a Boolean, it checks that an element matching the CSS selector exists.➔ If it is an integer, it checks that the CSS selector returns this number of results.➔ If it is a regular expression, it checks that the first element found by the CSS selector matches it.➔ If it is a regular expression preceded by !, it checks that the first element doesn't match the pattern.➔ For other cases, it compares the first element found by the CSS selector with the second argument as a string.

checkResponseElement ($selector, $value = true, $options = array())

checkResponseElement is incredibly powerful and can go much more in depth than this.http://www.symfony-project.org/book/1_1/15-Unit-and-Functional-Testing#Using CSS Selectors

$b = new sfTestBrowser();$b->get('/foobar/1')-> checkResponseElement('form input[type="hidden"][value="1"]', true);

Page 16: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

// Test directory structuretest/ functional/ frontend/ myModuleActionsTest.php myScenarioTest.php backend/ myOtherScenarioTest.php

## Run all functional tests for one application, recursively> symfony test-functional frontend

## Run one given functional test> symfony test-functional frontend myScenario

## Run several tests based on a pattern> symfony test-functional frontend my*

Putting It TogetherPutting It Together

Page 17: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

Using Lime Outside of SymfonyUsing Lime Outside of Symfony

Download/Checkout the Lime framework from: http://svn.symfony-project.com/tools/lime/trunk/lib/lime.php

require_once('/path/to/lime/lime.php');

Symfony Lime Documentation(and Cheatsheet):http://trac.symfony-project.org/wiki/LimeTestingFramework

Page 18: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

PHP Reflection APIPHP Reflection API

Requirements➔PHP Version >= 5➔The niche need to use it

What is it?A collection of classes and one interface to ”reverse-engineer” classes, interfaces, functions and methods.

Page 19: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

PHP Reflection APIPHP Reflection API

Classes in the Reflection API➔ReflectionException➔ReflectionFunction➔ReflectionParameter➔ReflectionClass➔ReflectionObject➔ReflectionMethod➔ReflectionProperty➔ReflectionExtension

Interfaces in the Reflection API➔Reflector

php.net/Reflection

Page 20: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

PHP Reflection APIPHP Reflection API

class Reflection { }interface Reflector { }class ReflectionException extends Exception { }class ReflectionFunction extends ReflectionFunctionAbstract

implements Reflector { }class ReflectionParameter implements Reflector { }class ReflectionMethod extends ReflectionFunctionAbstract

implements Reflector { }class ReflectionClass implements Reflector { }class ReflectionObject extends ReflectionClass { }class ReflectionProperty implements Reflector { }class ReflectionExtension implements Reflector { }

Heirarchy

Page 21: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

PHP Reflection APIPHP Reflection API

Recipe #1Checking for Function Documentation

$instance = new SomeClass();$refclass = new ReflectionClass($instance);$test->diag('Testing layout of '.get_class($instance));

$test->diag('Methods:');

//Check for documentationforeach($refclass->getMethods() as $method) { if($method->getDocComment() == '') { $test->output->red_bar(

sprintf('WARNING: %s does not have documentation',get_class($instance).'::'.$method->getName())

); } $doc_comment = $method->getDocComment(); if(preg_match_all('/(?<todo>TODO:.+)/', $doc_comment, $todos)) { $test->output->info(

sprintf("In method `%s`:", get_class($instance).'::'.$method->getName()));

foreach($todos['todo'] as $todo) { $test->output->info("\t".$todo); } }}

Page 22: Unit and Functional Testing in Symfony Introduction to ...files.meetup.com/225746/symfony_unit_functional_tests_reflection.pdf · What Unit Tests Are NOT For Unit tests are NOT human

PHP Reflection APIPHP Reflection API

Recipe #2Method Structure Testing