SlideShare une entreprise Scribd logo
1  sur  43
Training – Unit Testing with
PHP Unit
Ram Awadh
Presented By
Ram Awadh Prasad, PMP
Associate Principle Solution Architect
OSSCube
Email: ram.awadh@osscube.com
www.osscube.com
Introduction to Unit Testing
What is Unit Testing?
• A test is code that executes another piece of code (function/ method) in a known
context with knunit own inputs, and compares the output to the expected values.
• A method of testing that verifies the individual units of source code are working
properly
• Unit Testing is the testing of units (function or method). The tests are done to ensure
that each unit is working like it is intended to work.
Key Features of Unit Testing
• Automated testing
• Conducted at Regular Intervals
• Tests independent of each other
• Tests functional behavior – expected results & unexpected failures
Why Unit Testing – The Benefits
Benefits of Unit Testing:
• Think ahead of coding – understand the behavior before
writing code
• Test code on functionality and identify issues early
• Being automated, it saves overall effort and repetitive work
• Progress indication of the project
• Alerts generation for monitoring tools e.g. CI
• Facilitates code refactoring (change existing code without
changing behavior)
• Good documentation of how code works
Note: Refactoring is the process of changing a software
system in such a way that it does not alter the external
behavior of the code yet improves its internal structure. It is
a disciplined way to clean up code that minimizes the chances
of introducing bugs
Features of Good Unit Test
• Independent: Each test needs to run independently from
other tests and environments.
• Fast: To have useful tests and be able to run them as often
as possible, tests need to be fast.
• Repeatable: You should be able to run a test as many times
as you want with the same result.
• Up to date: Tests are written once, but code can be changed
or extended. Whenever this happens, tests should be
updated accordingly.
• Short: Tests should be just a few lines— easy to read and
understand.
• Resilient: Once written, tests shouldn't change till the
behavior of tested class/ method changes.
Writing Unit Tests – Some Guidelines
• When to write tests
› TDD or TFD: Write tests before writing any code.
› Write tests just after writing a class or method.
• How to write tests
› Test classes not methods – behavior is the key
› Do not write tests that do not test anything
› Do not write tests that test too much
› Exploit dependencies between tests
› Use the most specific assertion available to express what you
want to test
› Decouple test code from test data
PHPUnit
• Part of xUnit familiy (JUnit, SUnit,...)
• Created by Sebastian Bergmann
• Developed in PHP
• Initially released in March 2004
• Current release 5.3
• Integrated/supported by IDEs
› Zend Studio
› Zend Framework
› Netbeans
› Eclipse PDT
› PhpStorm
Installing PHPUnit
Installation Options
• Composer installation
• PEAR installation
• Linux package installation
• Manual installation
Anatomy of PHP Unit Test
• Test Classes
› Every PHP Unit test case is a class.
› The class name should end with Test.
› Every Test class inherits (most of the time) from
phpunitframeworkTestCase (or
PHPUnit_Framework_TestCase)
› Names and hierarchy of test classes should mirror the tested
class, with difference of ‘test’ in test class name.
• Test Methods
› The tests are public methods that are named test*.
› Alternatively, you can use the @test annotation in a method's
docblock to mark it as a test method.
› Inside the test methods, assertion methods such as
assertEquals() are used to assert that an actual value
matches an expected value.
Assertions
• An assertion is the heart and soul of unit testing.
• It is an assertion that a given value suits particular
constraint defined by the assert statement.
• The most basic assertions
› assertTrue(): This verifies that a condition is true
› assertFalse(): This verifies that a condition is false
› assertEquals(): This verifies that expected and actual values are
equal, the same way as the PHP comparison operator = =
› assertSame(): This is similar to assertEquals(), but it checks
whether values are identical, the same way as the = = = operator
› assertNull(): This verifies that value is null
› assertEmpty(): This verifies that value is empty, but it uses the PHP
function empty(), which means empty can be false, null, '', array()
• Complete list:
https://phpunit.de/manual/current/en/appendixes.assertion
s.html
Annotations
• An annotation is doc block comment used to annotate
source code.
• PHPUnit uses this information at runtime to configure
runtime behaviour.
• A doc comment in PHP must start with /** and end with
*/
• Examples:
• @backupGlobals
• @backupStaticAttributes
• @dataProvider
• @depends
Command line Runner
• Phpunit – command to run unit tests
• Usage:
› phpunit [options] UnitTest [UnitTest.php]
› phpunit [options] <directory>
• Examples
› phpunit UnitTest: Runs the tests that are provided by the
class UnitTest that inherits from phpunitframeworkTestCase
› phpunit UnitTest UnitTest.php: Runs the tests that are
provided by the class UnitTest. This class is expected to be
declared in the specified sourcefile.
• More options:
https://phpunit.de/manual/current/en/textui.html
Test Dependencies
• PHPUnit supports the declaration of explicit dependencies between test
methods.
• PHPUnit supports the declaration of explicit dependencies between test
methods.
• Dependencies do not define the order in which the test methods are to
be executed
• They allow the returning of an instance of the test fixture by a
producer and passing it to the dependent consumers.
• A producer is a test method that yields its unit under test as return
value.
• A consumer is a test method that depends on one or more producers
and their return values.
• PHPUnit uses @depends annotation to express dependencies.
• When a producer returns an object a reference to that object is passed
to the consumers.
• When a copy should be used instead of a reference then @depends
clone should be used instead of @depends.
• Example:
Data Providers
• Data Providers are used to pass arguments to methods that
need arbitrary arguments.
• Name of data provider method is specified using the
@dataProvider annotation.
• A data provider method must be public and
› either return an array of arrays or
› an object that implements the Iterator interface and yields an array
for each iteration step.
• All data providers are executed before both the call to the
setUpBeforeClass static method and the first call to the
setUp method.
Note: Iterator is an Interface for external iterators or objects that can be
iterated themselves internally.
Exercise – Testing ATM Class
• Create a simple ATM class with methods deposit
(deposit cash), withdraw (withdraw cash),
currentBalance (show current balance) and write unit
tests for the class.
• Use different basic assertions in tests
• Use @depends and @dataProvider options for
dependency and argument data
Testing Exceptions
• expectException() method is used to test if an exception is
thrown by the code under test.
• In addition expectExceptionCode(),
expectExceptionMessage(), and
expectExceptionMessageRegExp() methods exist to set up
expectations for exceptions raised by the code under test
• Alternatively, the annotations @expectedException,
@expectedExceptionCode, @expectedExceptionMessage,
and @expectedExceptionMessageRegExp can be used.
• Standard PHP exceptions:
http://php.net/manual/en/spl.exceptions.php
• Be as specific as possible when testing exceptions. Testing
for classes that are too generic might lead to undesirable
side-effects.
Testing PHP Errors
• PHP errors can be tested using exceptions as below:
• @expectedException PHPUnit_Framework_Error
• For notices and errors use
PHPUnit_Framework_Error_Notice and
PHPUnit_Framework_Error_Warning respectively
• Use error suppression while testing functions that
trigger errors like fopen
Testing Output
• PHPUnit uses PHP's Output Buffering feature to provide
the functionality of testing outputs of functions like
‘echo’ or ‘print’
• Following methods are used:
Method Meaning
void expectOutputRegex(string
$regularExpression)
Set up the expectation that the output
matches a$regularExpression.
void expectOutputString(string
$expectedString)
Set up the expectation that the output is
equal to an$expectedString.
bool setOutputCallback(callable $callback) Sets up a callback that is used to, for
instance, normalize the actual output.
Error Output & Edge Cases
• PHPUnit tries to be as specific as possible in reporting
issues when assertion fails.
• Uses textual representation of inputs for comparison
• This may result in reporting more issues / differences
than actual.
• Whenever a test fails PHPUnit tries its best to provide
you with as much context as possible that can help to
identify the problem but it may not be complete.
• E.g. when comparing long arrays, not all differences
may be reported.
• https://phpunit.de/manual/current/en/writing-tests-for-
phpunit.html#writing-tests-for-phpunit.exceptions
Fixtures
• When testing, we need to set the environment up to a
known state and cleanup when the test is complete.
• This known state is called the fixture of the test.
• As number and complexity of tests increases, fixture of
the test starts becoming cumbersome.
• It also leads to writing duplicate code for setting up and
cleaning objects.
• PHPUnit provides two options for defining fixtures:
› Set it before each test case class, runs once before and/ or
after each test case
› Set it before each test method, runs before each test and/ or
after each test
Fixtures - Before & After each method
• PHPUnit provides methods setUp() and tearDown() that
setup and clean objects before / after each test
method.
• The setUp() method is called before every test is
executed.
• The tearDown() method is opposite to setUp(), and it is
called when the test finishes.
• We need to implement tearDown() only if we have
allocated external resources like files or sockets in
setUp().
• If you have a bug in the code causing a fatal error,
tearDown() will not be called.
Fixtures – Before and After Class
• There are two other template methods:
setUpBeforeClass() and tearDownAfterClass()
• These are called before the first test of the test case
class is run and after the last test of the test case class
is run, respectively
• These methods can be used for setting resources that
need to be shared across test methods e.g. database
connections.
• Other considerations
› Variations in fixtures – ideally all tests in a case should have
same fixture
› Sharing fixtures – Generally not a good idea.. except for
specific cases
Global State
• Global state includes global variable like: $_GLOBALS, $_SERVER,
$_POST etc.
• It also includes static attributes of classes are also part of the
global state
• Undesirable effects of depending on global state:
› Unwanted side effects: One piece of code changes global state, while
another piece not expecting this change, behaves differently
› Hidden dependencies: It is difficult to spot required dependency, which is a
high risk when changing the code
› Not clearly defined responsibility: It is difficult to figure out how to test
when code might change behavior depending on change, which is difficult to
predict and replicate
• By default, PHPUnit runs your tests in a way where changes to
global and super-global variables do not affect other tests.
However, PHPUnit will not store and restore your $_SESSION data.
• It can be optionally extended to static variables
Global State
• Annotations and properties can used to control the backup and
restore operations for global variables
• Annotations
› @backupGlobals (enabled/disabled)
› @backupStaticAttributes
• Properties
› protected $ backupGlobals = true;
› protected $ backupGlobalsBlacklist = array('variable');
› protected $ backupStaticAttributes = true;
• You can provide a blacklist of global variables that are to be
excluded from the backup and restore operations using
$backupGlobalsBlacklist property.
• Setting the $backupGlobalsBlacklist property inside e.g. the
setUp() method has no effect. Hence it should not be tried.
Test Dependencies & Dependency Injection
• Discussion on problems due to test dependencies and
how to resolve them..
Test Doubles
• PHPUnit offers ways to modify the code on the fly and create test doubles.
• This feature allows create a double of your code (class) – a simplified version
– in order to remove dependencies and reduce complexity.
• Dependency may be due to other classes, Databases or third party APIs
• Allows to focus on testing the isolated code,
• Types of doubles:
› Dummy: Just an empty shell which is not called or used in itself. It is used only when
we need to pass things such as required arguments.
› Fake: This imitates the real object functionality, but is written and used only for tests.
› Stub: This returns predefined values for the method that is called or null for other
methods. Sometimes, they are also called indirect input to the tests.
› Spy: This is similar to the stub. It just remembers returned values that can be verified
later.
› Mock: The simplest definition of this double is a stub with expectations. An expectation
is the specification of the method on when and how it should be called during a test
execution.
Note: Final, private and static methods cannot be stubbed or mocked. They are
ignored by PHPUnit's test double functionality and retain their original behavior.
Creating Test Doubles
PHPUnit offers two basic ways of creating test doubles, which are as follows:
• $double = $ this-> getMock(' MyClass'); // This is deprecated now and createMock()
should be used.
• $double = $ this-> getMockBuilder(' MyClass')-> getMock();
The getMock() method accepts eight different (10 in Version 4) parameters, which affects how the
double will be created. They are described as follows:
• string $originalClassName: This is a class name from which the double will be created.
• array $methods: This will replace all methods by default and will return Null. If the name of the
methods are passed in an array, then only these methods will be replaced and the original
methods stay untouched.
• array $arguments: These arguments are used for the original constructor.
• string $mockClassName: This indicates the class name for the created test double.
• boolean $callOriginalConstructor: This is used when you want to enable/ disable the original
constructor call.
• boolean $callOriginalClone: This is used when you want to enable/ disable the original clone
method usage.
• boolean $callAutoload: This is used when you want to disable __autoload() for loading classes.
• boolean $cloneArguments: This allows to enable/ disable cloning of all object parameters.
Creating Test Doubles
PHPUnit Version 4 added two more arguments for test proxies, which are as
follows:
• boolean $ callOriginalMethods: This argument allows to call the original
methods, when test double is used Object
• $proxyTarget: This calls the original object for the test proxy
• Both of the methods do the same thing— create a test double— just in slightly
different ways.
› With the getMockBuilder() instead of passing 10 arguments, you can use method chaining to
set them up, as shown in the following code snippet:
$ double = $ this-> getMockBuilder(' MyClass')
-> enableOriginalClone()
-> enableArgumentCloning()
-> getMock();
Test Doubles – Fake and Dummy
Test Double - Stubs
• Practice of replacing an object with a test double that (optionally) returns
configured return values is referred to as stubbing
• E.g. // Create a stub for the SomeClass class.
$stub = $this->createMock(SomeClass::class);
// Configure the stub.
$stub->method('doSomething')
->willReturn('foo'); // or will($this->returnValue(‘foo’));
$this->assertEquals('foo', $stub->doSomething());
• Stub can also be configured to return a array map instead of single return.
E.g. $stub->method('doSomething')
• ->will($this->returnValueMap($map)); // $map is array of expected
inputs and return values.
• Stub can be used to return calculated value using a callback function. E.g.
$stub->method('doSomething')
->will($this->returnCallback('str_rot13')); // pass function name
• Limitation: There should not be method named "method“ in original class
Test Doubles – Mocking Objects
• The practice of replacing an object with a test double that verifies expectations, for instance asserting that a
method has been called, is referred to as mocking.
• We use the expects() and with() methods to specify how the interaction with Arguments should look. E.g.
$mock->expects($this->once()) // to be called only once
->method('update')
->with($this->equalTo('something'));
• Expectation has a functionality that asserts when and how a method is called. Its basic structure has the
following elements:
› expects: This shows how many times a method is called e.g any, never, atLeastOnce, once etc.
› method: This calls a method name
› with: This shows what needs to be passed to the method
› will: This shows what the method will return
• The with() method can take any number of arguments, corresponding to the number of arguments to the
method being mocked.
• The withConsecutive() method can take any number of arrays of arguments, depending on the calls you want to
test against. e.g.
withConsecutive(
[$this->equalTo('foo'), $this->greaterThan(0)],
[$this->equalTo('bar'), $this->greaterThan(0)]
);
• The callback() constraint can be used for more complex argument verification.
Test Doubles - Example
• Testing a sample transaction class that takes an array
input and post data to API in XML format.
• Includes following classes:
› Transaction – the class to be tested
› Logger – class for logging API action
› HTTPClient – class for interacting with the API
Mocking Other Class & Objects Types
• Abstract Class and Traits: PHPUnit provide special methods below for
mocking Traits and Abstract classes:
› getMockForTrait() - This method returns a mock object that uses a specified
trait. All abstract methods of the given trait are mocked. This allows for testing
the concrete methods of a trait.
› getMockForAbstractClass() - This method returns a mock object for an abstract
class. All abstract methods of the given abstract class are mocked. This allows
for testing the concrete methods of an abstract class.
• Web Services: The method getMockFromWsdl() can be used just like
getMock() to mock SOAP Web Services. It requires SOAP extension
enabled in PHP
• FileSystem: vfsStream is a stream wrapper for a virtual filesystem that
may be helpful in unit tests to mock the real filesystem.
› To use, add a dependency on mikey179/vfsStream to your project's
composer.json
› vfsStream gives the test developer full control over what the filesystem
environment looks like to the tested code.
› Since the filesystem operations do not operate on the real filesystem anymore,
cleanup operations in a tearDown() method are no longer required.
› Documentation url: https://github.com/mikey179/vfsStream/wiki
Stages of Database Testing
• The four stages of a database test
› Set up fixture: Putting database into a known state.
› Exercise System Under Test
› Verify outcome: : Asserting contents of the database are same as expected.
› Teardown: Clean up the database.
• Fixture: A fixture describes the initial state your application and database are
in when you execute a test.
• Testing the database requires you to hook into at least the setup and
teardown to clean-up and write the required fixture data into your tables.
• General stages in a database test resemble the following workflow that is
executed for each single test:
› 1. Clean-Up Database: Execute a TRUNCATE against all the tables specified to reset
their status to empty, to ensure clean database.
› 2. Set up fixture: Iterate over all the fixture rows specified and insert them into their
respective tables.
› 3–5. Run Test, Verify outcome and Teardown: After the database is reset and loaded
with its initial state the actual test is executed by PHPUnit.
Note: The part of the test code does not require awareness of the Database
Extension at all, you can go on and test whatever you like with your code.
DB Unit – PHP Unit’s extension for Database Testing
• DBUnit is a PHPUnit extension for DB testing
• To start with, extend the abstract class:
PHPUnit_Extensions_Database_TestCase.
• In this testcase we implement two abstract methods:
› getConnection(): This provides a database connection
wrapped in PHPUnit class - abstracted across vendors through
the PDO library
› It allows the clean-up and fixture loading functionalities to
work.
› getDataSet(): The getDataSet() method defines how the
initial state of the database should look before each test is
executed.
• The getDataSet() method is called once during setUp()
to retrieve the fixture data-set and insert it into the
Data Sets and Data Tables
• DBUnit uses the concepts DataSet and DataTable:
› DataSet: represented by interface
PHPUnit_Extensions_Database_DataSet_IDataSet
› DataTable: represented by interface
PHPUnit_Extensions_Database_DataSet_IDataTable.
• The DataSet and DataTable are an abstraction layer around database
tables, rows and columns.
• It hides the underlying database contents in an object structure, which
can also be implemented by other non-database sources.
• This abstraction is used to compare the actual contents of a database
against the expected contents.
• Expectations can be represented as XML, YAML, CSV files or PHP array
for example.
• The DataSet and DataTable interfaces enable the comparison of the
conceptually different sources, emulating relational database storage.
• We can also implement our own datasets and tables if the available
one’s do not meet our requirements.
Data Set Types
• There are three different types of basic datasets / data tables:
• File-Based DataSets and DataTables
› Flat XML DataSet: createFlatXmlDataSet($filename)
› XML DataSet:There is another more structured XML dataset, which is a bit more
verbose to write but avoids the NULL problems of the Flat XML -
>createXmlDataSet($filename)
› MySQL XML DataSet:This new XML format is specific to the MySQL database server. can
be generated using the mysqldump utility -> createMySQLXMLDataSet($filename)
› YAML DataSet:This is simple, convient AND it solves the NULL issue that the similar Flat
XML dataset has. A NULL in YAML is just the column name without no value specified.
The YAML Dataset has no factory method on the Database TestCase currently, so you
have to instantiate it manually.
› CSV DataSet:
› Array DataSet: There is no Array based DataSet in PHPUnit's Database Extension (yet),
but we can implement our own easily
• Query-Based DataSet and DataTable: For database assertions you do not only
need the file-based datasets but also a Query/SQL based Dataset that
contains the actual contents of the database.
$ds = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this-
>getConnection());
$ds->addTable('guestbook', 'SELECT * FROM guestbook');
Data Set Types
• Database (DB) Dataset: a DataSet that consists of all the tables with their
content in the database specified as second parameter to the Connections
Factory method.
› $tableNames = ['guestbook'];
› $dataSet = $this->getConnection()->createDataSet($tableNames);
• Other Data Sets: The content of the basic datasets can be modified by other
datasets below, which use them as inputs and then perform some operations
before returning a modified dataset
› Replacement DataSet: The Replacement DataSet is a decorator for an existing dataset
and allows you to replace values in any column of the dataset by another replacement
value.
› DataSet Filter: If you have a large fixture file you can use the DataSet Filter for white-
and blacklisting of tables and columns that should be contained in a sub-dataset.
◦ Blacklisting or white listing of tables / columns is done using include / exclude statements.
◦ However, both exclude and exclude cannot be used together
› Composite DataSet: The composite DataSet is very useful for aggregating several
already existing datasets into a single dataset.
Beware of Foreign Keys: The getDataSet() method is called once during setUp()
to retrieve the fixture data-set and insert it into the database. During Fixture
SetUp PHPUnit's Database Extension inserts the rows into the database in the
order they are specified in your fixture. If your database schema uses foreign
keys this means you have to specify the tables in an order that does not cause
foreign key constraints to fail.
Organizing Tests
Unit Tests should be composable. We should be able to run
any number or combination of tests together.
• Composing a Test Suite Using the Filesystem
› The test case classes in the tests directory mirror the package and
class structure of the System Under Test (SUT) in the src directory.
› Tests will be run on the basis of directory where phpunit is pointed.
› For more fine-grained control of which tests to run we can use the -
-filter option.
› A drawback of this approach is that we have no control over the
order in which the tests are run.
• Composing a Test Suite Using XML Configuration.
› Test composition can also be defined in phpunit.xml configuration
file.
› If phpunit.xml or phpunit.xml.dist (in that order) exist in the
current working directory and --configuration is not used, the
configuration will be automatically read from that file.
› The order in which tests are executed can be made explicit.
Risky Tests
PHPUnit can be configured to filter out risky tests e.g. tests that test nothing,
unintentional coverage, output during execution etc. Following options are available:
Effect Command line
option
XML Configuration
A test that does not perform an assertion will be
marked as risky when this check is enabled
--report-useless-
tests
beStrictAboutTestsThatDoNotT
estAnything="true"
A test that is annotated with @covers and executes
code that is not listed using
a @covers or @uses annotation will be marked as
risky
--strict-coverage checkForUnintentionallyCovere
dCode="true"
A time limit can be enforced for the execution of a
test. Tests can be annotated as @small, @medium
or @large with pre configured timeout for each.
--enforce-time-limit beStrictAboutTestSize="true"
Tests that manipulate Global State. --strict-global-state beStrictAboutChangesToGlobal
State="true"
Incomplete and Skipped Tests
Incomplete Tests
• PHPUnit allows marking test as incomplete if it is not completely
implemented yet.
• Following methods are available:
› markTestIncomplete(): Marks the current test as incomplete.
› markTestIncomplete(string $message): Marks the current test as incomplete
using $message as an explanatory message.
Skipped Tests
• Allows marking tests as skipped.
› void markTestSkipped():Marks the current test as skipped.
› void markTestSkipped(string $message): Marks the current test as skipped
using $message as an explanatory message.
• Tests can be skipped for various reasons like any dependency,
incompleteness etc.
• It is also possible to use the @requires annotation to express common
preconditions for a test case and skipping if needed.
Unit Test Best Practices
• Use most specific assertion for a given case.
• Test method name should reflect what it is intended to test.
• Write small and precise tests to have fast test suite.
• Organize your tests well using either file system or
phpunit.xml config.
• Separate unit tests, functional tests and integration tests.
• Bootstrap only what you need
• Test classes not methods – observable behavior from
outside the class e.g.
› Return values
› Method calls to other objects
› Global state
Code Coverage

Contenu connexe

Tendances

Unit Testing And Mocking
Unit Testing And MockingUnit Testing And Mocking
Unit Testing And Mocking
Joe Wilson
 
Guide pratique openssl sous debian
Guide pratique openssl sous debianGuide pratique openssl sous debian
Guide pratique openssl sous debian
yahyaf10
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
nickokiss
 

Tendances (20)

Manipulação de formulários com PHP. Uso de Cookies e Session com PHP.
Manipulação de formulários com PHP. Uso de Cookies e Session com PHP.Manipulação de formulários com PHP. Uso de Cookies e Session com PHP.
Manipulação de formulários com PHP. Uso de Cookies e Session com PHP.
 
TestNG Session presented in PB
TestNG Session presented in PBTestNG Session presented in PB
TestNG Session presented in PB
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
The World of PHP PSR Standards
The World of PHP PSR StandardsThe World of PHP PSR Standards
The World of PHP PSR Standards
 
Unit Testing And Mocking
Unit Testing And MockingUnit Testing And Mocking
Unit Testing And Mocking
 
Unit Testing in Java
Unit Testing in JavaUnit Testing in Java
Unit Testing in Java
 
PHP Powerpoint -- Teach PHP with this
PHP Powerpoint -- Teach PHP with thisPHP Powerpoint -- Teach PHP with this
PHP Powerpoint -- Teach PHP with this
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
 
TestNG Framework
TestNG Framework TestNG Framework
TestNG Framework
 
Selenium IDE LOCATORS
Selenium IDE LOCATORSSelenium IDE LOCATORS
Selenium IDE LOCATORS
 
TestNG - The Next Generation of Unit Testing
TestNG - The Next Generation of Unit TestingTestNG - The Next Generation of Unit Testing
TestNG - The Next Generation of Unit Testing
 
Locators in selenium - BNT 09
Locators in selenium - BNT 09Locators in selenium - BNT 09
Locators in selenium - BNT 09
 
Java. Explicit and Implicit Wait. Testing Ajax Applications
Java. Explicit and Implicit Wait. Testing Ajax ApplicationsJava. Explicit and Implicit Wait. Testing Ajax Applications
Java. Explicit and Implicit Wait. Testing Ajax Applications
 
Data Driven Framework in Selenium
Data Driven Framework in SeleniumData Driven Framework in Selenium
Data Driven Framework in Selenium
 
REST API 설계
REST API 설계REST API 설계
REST API 설계
 
Guide pratique openssl sous debian
Guide pratique openssl sous debianGuide pratique openssl sous debian
Guide pratique openssl sous debian
 
Unit testing best practices
Unit testing best practicesUnit testing best practices
Unit testing best practices
 
Introduction to laravel framework
Introduction to laravel frameworkIntroduction to laravel framework
Introduction to laravel framework
 
TestNG with selenium
TestNG with seleniumTestNG with selenium
TestNG with selenium
 
Zeronights 2016 | A blow under the belt. How to avoid WAF/IPS/DLP | Удар ниже...
Zeronights 2016 | A blow under the belt. How to avoid WAF/IPS/DLP | Удар ниже...Zeronights 2016 | A blow under the belt. How to avoid WAF/IPS/DLP | Удар ниже...
Zeronights 2016 | A blow under the belt. How to avoid WAF/IPS/DLP | Удар ниже...
 

En vedette

Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnit
Peter Wilcsinszky
 
Top 8 chief business development officer resume samples
Top 8 chief business development officer resume samplesTop 8 chief business development officer resume samples
Top 8 chief business development officer resume samples
porichfergu
 
Tool room & engineering manager
Tool room & engineering managerTool room & engineering manager
Tool room & engineering manager
rislam2008
 

En vedette (20)

Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnit
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
AngularJS und TYP-D'oh!3
AngularJS und TYP-D'oh!3AngularJS und TYP-D'oh!3
AngularJS und TYP-D'oh!3
 
How to test models using php unit testing framework?
How to test models using php unit testing framework?How to test models using php unit testing framework?
How to test models using php unit testing framework?
 
Installation instruction of Testlink
Installation instruction of TestlinkInstallation instruction of Testlink
Installation instruction of Testlink
 
Automated Testing in WordPress, Really?!
Automated Testing in WordPress, Really?!Automated Testing in WordPress, Really?!
Automated Testing in WordPress, Really?!
 
Mt on leadership and its effects on employees performance
Mt on   leadership and its effects on employees performanceMt on   leadership and its effects on employees performance
Mt on leadership and its effects on employees performance
 
Intergenerational Networking
Intergenerational NetworkingIntergenerational Networking
Intergenerational Networking
 
Top 8 chief business development officer resume samples
Top 8 chief business development officer resume samplesTop 8 chief business development officer resume samples
Top 8 chief business development officer resume samples
 
rgl test
rgl testrgl test
rgl test
 
posititude - Dec 14
posititude - Dec 14posititude - Dec 14
posititude - Dec 14
 
Tool room & engineering manager
Tool room & engineering managerTool room & engineering manager
Tool room & engineering manager
 
米羅
米羅米羅
米羅
 
Beijing2011
Beijing2011Beijing2011
Beijing2011
 
Bab 5 9d
Bab 5 9dBab 5 9d
Bab 5 9d
 
NOVEL 2
NOVEL 2NOVEL 2
NOVEL 2
 
Micro Coat Sd0802 C Die Stacking
Micro Coat Sd0802 C Die StackingMicro Coat Sd0802 C Die Stacking
Micro Coat Sd0802 C Die Stacking
 
Power grid
Power gridPower grid
Power grid
 
China Optical Expo on Barter
China Optical Expo on BarterChina Optical Expo on Barter
China Optical Expo on Barter
 
Ts 2992
Ts 2992Ts 2992
Ts 2992
 

Similaire à Unit Testng with PHP Unit - A Step by Step Training

Unit testing php-unit - phing - selenium_v2
Unit testing   php-unit - phing - selenium_v2Unit testing   php-unit - phing - selenium_v2
Unit testing php-unit - phing - selenium_v2
Tricode (part of Dept)
 
Test-Driven Development
Test-Driven DevelopmentTest-Driven Development
Test-Driven Development
Meilan Ou
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
Yi-Huan Chan
 
Into The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applicationsInto The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applications
Ortus Solutions, Corp
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1
Yi-Huan Chan
 

Similaire à Unit Testng with PHP Unit - A Step by Step Training (20)

Introduction to JUnit
Introduction to JUnitIntroduction to JUnit
Introduction to JUnit
 
Unit testing php-unit - phing - selenium_v2
Unit testing   php-unit - phing - selenium_v2Unit testing   php-unit - phing - selenium_v2
Unit testing php-unit - phing - selenium_v2
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
 
Test automation principles, terminologies and implementations
Test automation principles, terminologies and implementationsTest automation principles, terminologies and implementations
Test automation principles, terminologies and implementations
 
An Introduction to Unit Test Using NUnit
An Introduction to Unit Test Using NUnitAn Introduction to Unit Test Using NUnit
An Introduction to Unit Test Using NUnit
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
 
Principles and patterns for test driven development
Principles and patterns for test driven developmentPrinciples and patterns for test driven development
Principles and patterns for test driven development
 
Database Unit Testing Made Easy with VSTS
Database Unit Testing Made Easy with VSTSDatabase Unit Testing Made Easy with VSTS
Database Unit Testing Made Easy with VSTS
 
Test-Driven Development
Test-Driven DevelopmentTest-Driven Development
Test-Driven Development
 
Unit testing
Unit testingUnit testing
Unit testing
 
unit 1 (1).pptx
unit 1 (1).pptxunit 1 (1).pptx
unit 1 (1).pptx
 
Java Unit Test - JUnit
Java Unit Test - JUnitJava Unit Test - JUnit
Java Unit Test - JUnit
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
Software Testing
Software TestingSoftware Testing
Software Testing
 
Into The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applicationsInto The Box 2018 | Assert control over your legacy applications
Into The Box 2018 | Assert control over your legacy applications
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Junit
JunitJunit
Junit
 
Unit testing in Force.com platform
Unit testing in Force.com platformUnit testing in Force.com platform
Unit testing in Force.com platform
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1
 
"Introduction to JMeter" @ CPTM 3rd Session
"Introduction to JMeter" @ CPTM 3rd Session"Introduction to JMeter" @ CPTM 3rd Session
"Introduction to JMeter" @ CPTM 3rd Session
 

Dernier

Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+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
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 

Dernier (20)

WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
Abortion Pill Prices Boksburg [(+27832195400*)] 🏥 Women's Abortion Clinic in ...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
%+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...
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
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
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 

Unit Testng with PHP Unit - A Step by Step Training

  • 1. Training – Unit Testing with PHP Unit Ram Awadh
  • 2. Presented By Ram Awadh Prasad, PMP Associate Principle Solution Architect OSSCube Email: ram.awadh@osscube.com www.osscube.com
  • 3. Introduction to Unit Testing What is Unit Testing? • A test is code that executes another piece of code (function/ method) in a known context with knunit own inputs, and compares the output to the expected values. • A method of testing that verifies the individual units of source code are working properly • Unit Testing is the testing of units (function or method). The tests are done to ensure that each unit is working like it is intended to work. Key Features of Unit Testing • Automated testing • Conducted at Regular Intervals • Tests independent of each other • Tests functional behavior – expected results & unexpected failures
  • 4. Why Unit Testing – The Benefits Benefits of Unit Testing: • Think ahead of coding – understand the behavior before writing code • Test code on functionality and identify issues early • Being automated, it saves overall effort and repetitive work • Progress indication of the project • Alerts generation for monitoring tools e.g. CI • Facilitates code refactoring (change existing code without changing behavior) • Good documentation of how code works Note: Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure. It is a disciplined way to clean up code that minimizes the chances of introducing bugs
  • 5. Features of Good Unit Test • Independent: Each test needs to run independently from other tests and environments. • Fast: To have useful tests and be able to run them as often as possible, tests need to be fast. • Repeatable: You should be able to run a test as many times as you want with the same result. • Up to date: Tests are written once, but code can be changed or extended. Whenever this happens, tests should be updated accordingly. • Short: Tests should be just a few lines— easy to read and understand. • Resilient: Once written, tests shouldn't change till the behavior of tested class/ method changes.
  • 6. Writing Unit Tests – Some Guidelines • When to write tests › TDD or TFD: Write tests before writing any code. › Write tests just after writing a class or method. • How to write tests › Test classes not methods – behavior is the key › Do not write tests that do not test anything › Do not write tests that test too much › Exploit dependencies between tests › Use the most specific assertion available to express what you want to test › Decouple test code from test data
  • 7. PHPUnit • Part of xUnit familiy (JUnit, SUnit,...) • Created by Sebastian Bergmann • Developed in PHP • Initially released in March 2004 • Current release 5.3 • Integrated/supported by IDEs › Zend Studio › Zend Framework › Netbeans › Eclipse PDT › PhpStorm
  • 8. Installing PHPUnit Installation Options • Composer installation • PEAR installation • Linux package installation • Manual installation
  • 9. Anatomy of PHP Unit Test • Test Classes › Every PHP Unit test case is a class. › The class name should end with Test. › Every Test class inherits (most of the time) from phpunitframeworkTestCase (or PHPUnit_Framework_TestCase) › Names and hierarchy of test classes should mirror the tested class, with difference of ‘test’ in test class name. • Test Methods › The tests are public methods that are named test*. › Alternatively, you can use the @test annotation in a method's docblock to mark it as a test method. › Inside the test methods, assertion methods such as assertEquals() are used to assert that an actual value matches an expected value.
  • 10. Assertions • An assertion is the heart and soul of unit testing. • It is an assertion that a given value suits particular constraint defined by the assert statement. • The most basic assertions › assertTrue(): This verifies that a condition is true › assertFalse(): This verifies that a condition is false › assertEquals(): This verifies that expected and actual values are equal, the same way as the PHP comparison operator = = › assertSame(): This is similar to assertEquals(), but it checks whether values are identical, the same way as the = = = operator › assertNull(): This verifies that value is null › assertEmpty(): This verifies that value is empty, but it uses the PHP function empty(), which means empty can be false, null, '', array() • Complete list: https://phpunit.de/manual/current/en/appendixes.assertion s.html
  • 11. Annotations • An annotation is doc block comment used to annotate source code. • PHPUnit uses this information at runtime to configure runtime behaviour. • A doc comment in PHP must start with /** and end with */ • Examples: • @backupGlobals • @backupStaticAttributes • @dataProvider • @depends
  • 12. Command line Runner • Phpunit – command to run unit tests • Usage: › phpunit [options] UnitTest [UnitTest.php] › phpunit [options] <directory> • Examples › phpunit UnitTest: Runs the tests that are provided by the class UnitTest that inherits from phpunitframeworkTestCase › phpunit UnitTest UnitTest.php: Runs the tests that are provided by the class UnitTest. This class is expected to be declared in the specified sourcefile. • More options: https://phpunit.de/manual/current/en/textui.html
  • 13. Test Dependencies • PHPUnit supports the declaration of explicit dependencies between test methods. • PHPUnit supports the declaration of explicit dependencies between test methods. • Dependencies do not define the order in which the test methods are to be executed • They allow the returning of an instance of the test fixture by a producer and passing it to the dependent consumers. • A producer is a test method that yields its unit under test as return value. • A consumer is a test method that depends on one or more producers and their return values. • PHPUnit uses @depends annotation to express dependencies. • When a producer returns an object a reference to that object is passed to the consumers. • When a copy should be used instead of a reference then @depends clone should be used instead of @depends. • Example:
  • 14. Data Providers • Data Providers are used to pass arguments to methods that need arbitrary arguments. • Name of data provider method is specified using the @dataProvider annotation. • A data provider method must be public and › either return an array of arrays or › an object that implements the Iterator interface and yields an array for each iteration step. • All data providers are executed before both the call to the setUpBeforeClass static method and the first call to the setUp method. Note: Iterator is an Interface for external iterators or objects that can be iterated themselves internally.
  • 15. Exercise – Testing ATM Class • Create a simple ATM class with methods deposit (deposit cash), withdraw (withdraw cash), currentBalance (show current balance) and write unit tests for the class. • Use different basic assertions in tests • Use @depends and @dataProvider options for dependency and argument data
  • 16. Testing Exceptions • expectException() method is used to test if an exception is thrown by the code under test. • In addition expectExceptionCode(), expectExceptionMessage(), and expectExceptionMessageRegExp() methods exist to set up expectations for exceptions raised by the code under test • Alternatively, the annotations @expectedException, @expectedExceptionCode, @expectedExceptionMessage, and @expectedExceptionMessageRegExp can be used. • Standard PHP exceptions: http://php.net/manual/en/spl.exceptions.php • Be as specific as possible when testing exceptions. Testing for classes that are too generic might lead to undesirable side-effects.
  • 17. Testing PHP Errors • PHP errors can be tested using exceptions as below: • @expectedException PHPUnit_Framework_Error • For notices and errors use PHPUnit_Framework_Error_Notice and PHPUnit_Framework_Error_Warning respectively • Use error suppression while testing functions that trigger errors like fopen
  • 18. Testing Output • PHPUnit uses PHP's Output Buffering feature to provide the functionality of testing outputs of functions like ‘echo’ or ‘print’ • Following methods are used: Method Meaning void expectOutputRegex(string $regularExpression) Set up the expectation that the output matches a$regularExpression. void expectOutputString(string $expectedString) Set up the expectation that the output is equal to an$expectedString. bool setOutputCallback(callable $callback) Sets up a callback that is used to, for instance, normalize the actual output.
  • 19. Error Output & Edge Cases • PHPUnit tries to be as specific as possible in reporting issues when assertion fails. • Uses textual representation of inputs for comparison • This may result in reporting more issues / differences than actual. • Whenever a test fails PHPUnit tries its best to provide you with as much context as possible that can help to identify the problem but it may not be complete. • E.g. when comparing long arrays, not all differences may be reported. • https://phpunit.de/manual/current/en/writing-tests-for- phpunit.html#writing-tests-for-phpunit.exceptions
  • 20. Fixtures • When testing, we need to set the environment up to a known state and cleanup when the test is complete. • This known state is called the fixture of the test. • As number and complexity of tests increases, fixture of the test starts becoming cumbersome. • It also leads to writing duplicate code for setting up and cleaning objects. • PHPUnit provides two options for defining fixtures: › Set it before each test case class, runs once before and/ or after each test case › Set it before each test method, runs before each test and/ or after each test
  • 21. Fixtures - Before & After each method • PHPUnit provides methods setUp() and tearDown() that setup and clean objects before / after each test method. • The setUp() method is called before every test is executed. • The tearDown() method is opposite to setUp(), and it is called when the test finishes. • We need to implement tearDown() only if we have allocated external resources like files or sockets in setUp(). • If you have a bug in the code causing a fatal error, tearDown() will not be called.
  • 22. Fixtures – Before and After Class • There are two other template methods: setUpBeforeClass() and tearDownAfterClass() • These are called before the first test of the test case class is run and after the last test of the test case class is run, respectively • These methods can be used for setting resources that need to be shared across test methods e.g. database connections. • Other considerations › Variations in fixtures – ideally all tests in a case should have same fixture › Sharing fixtures – Generally not a good idea.. except for specific cases
  • 23. Global State • Global state includes global variable like: $_GLOBALS, $_SERVER, $_POST etc. • It also includes static attributes of classes are also part of the global state • Undesirable effects of depending on global state: › Unwanted side effects: One piece of code changes global state, while another piece not expecting this change, behaves differently › Hidden dependencies: It is difficult to spot required dependency, which is a high risk when changing the code › Not clearly defined responsibility: It is difficult to figure out how to test when code might change behavior depending on change, which is difficult to predict and replicate • By default, PHPUnit runs your tests in a way where changes to global and super-global variables do not affect other tests. However, PHPUnit will not store and restore your $_SESSION data. • It can be optionally extended to static variables
  • 24. Global State • Annotations and properties can used to control the backup and restore operations for global variables • Annotations › @backupGlobals (enabled/disabled) › @backupStaticAttributes • Properties › protected $ backupGlobals = true; › protected $ backupGlobalsBlacklist = array('variable'); › protected $ backupStaticAttributes = true; • You can provide a blacklist of global variables that are to be excluded from the backup and restore operations using $backupGlobalsBlacklist property. • Setting the $backupGlobalsBlacklist property inside e.g. the setUp() method has no effect. Hence it should not be tried.
  • 25. Test Dependencies & Dependency Injection • Discussion on problems due to test dependencies and how to resolve them..
  • 26. Test Doubles • PHPUnit offers ways to modify the code on the fly and create test doubles. • This feature allows create a double of your code (class) – a simplified version – in order to remove dependencies and reduce complexity. • Dependency may be due to other classes, Databases or third party APIs • Allows to focus on testing the isolated code, • Types of doubles: › Dummy: Just an empty shell which is not called or used in itself. It is used only when we need to pass things such as required arguments. › Fake: This imitates the real object functionality, but is written and used only for tests. › Stub: This returns predefined values for the method that is called or null for other methods. Sometimes, they are also called indirect input to the tests. › Spy: This is similar to the stub. It just remembers returned values that can be verified later. › Mock: The simplest definition of this double is a stub with expectations. An expectation is the specification of the method on when and how it should be called during a test execution. Note: Final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.
  • 27. Creating Test Doubles PHPUnit offers two basic ways of creating test doubles, which are as follows: • $double = $ this-> getMock(' MyClass'); // This is deprecated now and createMock() should be used. • $double = $ this-> getMockBuilder(' MyClass')-> getMock(); The getMock() method accepts eight different (10 in Version 4) parameters, which affects how the double will be created. They are described as follows: • string $originalClassName: This is a class name from which the double will be created. • array $methods: This will replace all methods by default and will return Null. If the name of the methods are passed in an array, then only these methods will be replaced and the original methods stay untouched. • array $arguments: These arguments are used for the original constructor. • string $mockClassName: This indicates the class name for the created test double. • boolean $callOriginalConstructor: This is used when you want to enable/ disable the original constructor call. • boolean $callOriginalClone: This is used when you want to enable/ disable the original clone method usage. • boolean $callAutoload: This is used when you want to disable __autoload() for loading classes. • boolean $cloneArguments: This allows to enable/ disable cloning of all object parameters.
  • 28. Creating Test Doubles PHPUnit Version 4 added two more arguments for test proxies, which are as follows: • boolean $ callOriginalMethods: This argument allows to call the original methods, when test double is used Object • $proxyTarget: This calls the original object for the test proxy • Both of the methods do the same thing— create a test double— just in slightly different ways. › With the getMockBuilder() instead of passing 10 arguments, you can use method chaining to set them up, as shown in the following code snippet: $ double = $ this-> getMockBuilder(' MyClass') -> enableOriginalClone() -> enableArgumentCloning() -> getMock();
  • 29. Test Doubles – Fake and Dummy
  • 30. Test Double - Stubs • Practice of replacing an object with a test double that (optionally) returns configured return values is referred to as stubbing • E.g. // Create a stub for the SomeClass class. $stub = $this->createMock(SomeClass::class); // Configure the stub. $stub->method('doSomething') ->willReturn('foo'); // or will($this->returnValue(‘foo’)); $this->assertEquals('foo', $stub->doSomething()); • Stub can also be configured to return a array map instead of single return. E.g. $stub->method('doSomething') • ->will($this->returnValueMap($map)); // $map is array of expected inputs and return values. • Stub can be used to return calculated value using a callback function. E.g. $stub->method('doSomething') ->will($this->returnCallback('str_rot13')); // pass function name • Limitation: There should not be method named "method“ in original class
  • 31. Test Doubles – Mocking Objects • The practice of replacing an object with a test double that verifies expectations, for instance asserting that a method has been called, is referred to as mocking. • We use the expects() and with() methods to specify how the interaction with Arguments should look. E.g. $mock->expects($this->once()) // to be called only once ->method('update') ->with($this->equalTo('something')); • Expectation has a functionality that asserts when and how a method is called. Its basic structure has the following elements: › expects: This shows how many times a method is called e.g any, never, atLeastOnce, once etc. › method: This calls a method name › with: This shows what needs to be passed to the method › will: This shows what the method will return • The with() method can take any number of arguments, corresponding to the number of arguments to the method being mocked. • The withConsecutive() method can take any number of arrays of arguments, depending on the calls you want to test against. e.g. withConsecutive( [$this->equalTo('foo'), $this->greaterThan(0)], [$this->equalTo('bar'), $this->greaterThan(0)] ); • The callback() constraint can be used for more complex argument verification.
  • 32. Test Doubles - Example • Testing a sample transaction class that takes an array input and post data to API in XML format. • Includes following classes: › Transaction – the class to be tested › Logger – class for logging API action › HTTPClient – class for interacting with the API
  • 33. Mocking Other Class & Objects Types • Abstract Class and Traits: PHPUnit provide special methods below for mocking Traits and Abstract classes: › getMockForTrait() - This method returns a mock object that uses a specified trait. All abstract methods of the given trait are mocked. This allows for testing the concrete methods of a trait. › getMockForAbstractClass() - This method returns a mock object for an abstract class. All abstract methods of the given abstract class are mocked. This allows for testing the concrete methods of an abstract class. • Web Services: The method getMockFromWsdl() can be used just like getMock() to mock SOAP Web Services. It requires SOAP extension enabled in PHP • FileSystem: vfsStream is a stream wrapper for a virtual filesystem that may be helpful in unit tests to mock the real filesystem. › To use, add a dependency on mikey179/vfsStream to your project's composer.json › vfsStream gives the test developer full control over what the filesystem environment looks like to the tested code. › Since the filesystem operations do not operate on the real filesystem anymore, cleanup operations in a tearDown() method are no longer required. › Documentation url: https://github.com/mikey179/vfsStream/wiki
  • 34. Stages of Database Testing • The four stages of a database test › Set up fixture: Putting database into a known state. › Exercise System Under Test › Verify outcome: : Asserting contents of the database are same as expected. › Teardown: Clean up the database. • Fixture: A fixture describes the initial state your application and database are in when you execute a test. • Testing the database requires you to hook into at least the setup and teardown to clean-up and write the required fixture data into your tables. • General stages in a database test resemble the following workflow that is executed for each single test: › 1. Clean-Up Database: Execute a TRUNCATE against all the tables specified to reset their status to empty, to ensure clean database. › 2. Set up fixture: Iterate over all the fixture rows specified and insert them into their respective tables. › 3–5. Run Test, Verify outcome and Teardown: After the database is reset and loaded with its initial state the actual test is executed by PHPUnit. Note: The part of the test code does not require awareness of the Database Extension at all, you can go on and test whatever you like with your code.
  • 35. DB Unit – PHP Unit’s extension for Database Testing • DBUnit is a PHPUnit extension for DB testing • To start with, extend the abstract class: PHPUnit_Extensions_Database_TestCase. • In this testcase we implement two abstract methods: › getConnection(): This provides a database connection wrapped in PHPUnit class - abstracted across vendors through the PDO library › It allows the clean-up and fixture loading functionalities to work. › getDataSet(): The getDataSet() method defines how the initial state of the database should look before each test is executed. • The getDataSet() method is called once during setUp() to retrieve the fixture data-set and insert it into the
  • 36. Data Sets and Data Tables • DBUnit uses the concepts DataSet and DataTable: › DataSet: represented by interface PHPUnit_Extensions_Database_DataSet_IDataSet › DataTable: represented by interface PHPUnit_Extensions_Database_DataSet_IDataTable. • The DataSet and DataTable are an abstraction layer around database tables, rows and columns. • It hides the underlying database contents in an object structure, which can also be implemented by other non-database sources. • This abstraction is used to compare the actual contents of a database against the expected contents. • Expectations can be represented as XML, YAML, CSV files or PHP array for example. • The DataSet and DataTable interfaces enable the comparison of the conceptually different sources, emulating relational database storage. • We can also implement our own datasets and tables if the available one’s do not meet our requirements.
  • 37. Data Set Types • There are three different types of basic datasets / data tables: • File-Based DataSets and DataTables › Flat XML DataSet: createFlatXmlDataSet($filename) › XML DataSet:There is another more structured XML dataset, which is a bit more verbose to write but avoids the NULL problems of the Flat XML - >createXmlDataSet($filename) › MySQL XML DataSet:This new XML format is specific to the MySQL database server. can be generated using the mysqldump utility -> createMySQLXMLDataSet($filename) › YAML DataSet:This is simple, convient AND it solves the NULL issue that the similar Flat XML dataset has. A NULL in YAML is just the column name without no value specified. The YAML Dataset has no factory method on the Database TestCase currently, so you have to instantiate it manually. › CSV DataSet: › Array DataSet: There is no Array based DataSet in PHPUnit's Database Extension (yet), but we can implement our own easily • Query-Based DataSet and DataTable: For database assertions you do not only need the file-based datasets but also a Query/SQL based Dataset that contains the actual contents of the database. $ds = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this- >getConnection()); $ds->addTable('guestbook', 'SELECT * FROM guestbook');
  • 38. Data Set Types • Database (DB) Dataset: a DataSet that consists of all the tables with their content in the database specified as second parameter to the Connections Factory method. › $tableNames = ['guestbook']; › $dataSet = $this->getConnection()->createDataSet($tableNames); • Other Data Sets: The content of the basic datasets can be modified by other datasets below, which use them as inputs and then perform some operations before returning a modified dataset › Replacement DataSet: The Replacement DataSet is a decorator for an existing dataset and allows you to replace values in any column of the dataset by another replacement value. › DataSet Filter: If you have a large fixture file you can use the DataSet Filter for white- and blacklisting of tables and columns that should be contained in a sub-dataset. ◦ Blacklisting or white listing of tables / columns is done using include / exclude statements. ◦ However, both exclude and exclude cannot be used together › Composite DataSet: The composite DataSet is very useful for aggregating several already existing datasets into a single dataset. Beware of Foreign Keys: The getDataSet() method is called once during setUp() to retrieve the fixture data-set and insert it into the database. During Fixture SetUp PHPUnit's Database Extension inserts the rows into the database in the order they are specified in your fixture. If your database schema uses foreign keys this means you have to specify the tables in an order that does not cause foreign key constraints to fail.
  • 39. Organizing Tests Unit Tests should be composable. We should be able to run any number or combination of tests together. • Composing a Test Suite Using the Filesystem › The test case classes in the tests directory mirror the package and class structure of the System Under Test (SUT) in the src directory. › Tests will be run on the basis of directory where phpunit is pointed. › For more fine-grained control of which tests to run we can use the - -filter option. › A drawback of this approach is that we have no control over the order in which the tests are run. • Composing a Test Suite Using XML Configuration. › Test composition can also be defined in phpunit.xml configuration file. › If phpunit.xml or phpunit.xml.dist (in that order) exist in the current working directory and --configuration is not used, the configuration will be automatically read from that file. › The order in which tests are executed can be made explicit.
  • 40. Risky Tests PHPUnit can be configured to filter out risky tests e.g. tests that test nothing, unintentional coverage, output during execution etc. Following options are available: Effect Command line option XML Configuration A test that does not perform an assertion will be marked as risky when this check is enabled --report-useless- tests beStrictAboutTestsThatDoNotT estAnything="true" A test that is annotated with @covers and executes code that is not listed using a @covers or @uses annotation will be marked as risky --strict-coverage checkForUnintentionallyCovere dCode="true" A time limit can be enforced for the execution of a test. Tests can be annotated as @small, @medium or @large with pre configured timeout for each. --enforce-time-limit beStrictAboutTestSize="true" Tests that manipulate Global State. --strict-global-state beStrictAboutChangesToGlobal State="true"
  • 41. Incomplete and Skipped Tests Incomplete Tests • PHPUnit allows marking test as incomplete if it is not completely implemented yet. • Following methods are available: › markTestIncomplete(): Marks the current test as incomplete. › markTestIncomplete(string $message): Marks the current test as incomplete using $message as an explanatory message. Skipped Tests • Allows marking tests as skipped. › void markTestSkipped():Marks the current test as skipped. › void markTestSkipped(string $message): Marks the current test as skipped using $message as an explanatory message. • Tests can be skipped for various reasons like any dependency, incompleteness etc. • It is also possible to use the @requires annotation to express common preconditions for a test case and skipping if needed.
  • 42. Unit Test Best Practices • Use most specific assertion for a given case. • Test method name should reflect what it is intended to test. • Write small and precise tests to have fast test suite. • Organize your tests well using either file system or phpunit.xml config. • Separate unit tests, functional tests and integration tests. • Bootstrap only what you need • Test classes not methods – observable behavior from outside the class e.g. › Return values › Method calls to other objects › Global state