More Related Content Similar to Unit testing PHP apps with PHPUnit (20) More from Michelangelo van Dam (20) Unit testing PHP apps with PHPUnit4. Excuses
not
to
test
• No
6me
• Not
in
budget
• We
don’t
know
how
-‐
valid
and
honest
answer
-‐
right,
like
that’s
going
to
happen
• We
add
unit
tests
a@er
finish
project
•…
4
6. Unit
tes6ng
is
fun
and
easy!
• When
you
write
code
• You
already
test
in
your
head
• Write
out
these
test(s)
• And
protect
your
code
base
6
8. My
example
code
• Get
this
example
from
GitHub
-‐
hQps://github.com/in2it/Utexamples
project/
src/
Utexamples/
Calculator.php
autoload.php
tests/
Utexamples/
CalculatorTest.php
8
9. Simple
example
class
• Add
by
one
-‐ adds
the
current
value
by
one
?php !
namespace Utexamples; !
!
/** !
* Class that allows us to make all sorts of calculations !
*/ !
class Calculator !
{ !
protected $_value = 0; !
!
/** !
* Adds the current value by one !
* !
* @return int The value from this method !
*/ !
public function addByOne() !
{ !
$this-_value++; !
return $this-_value; !
} !
}
9
10. Our
unit
test
?php !
namespace Utexamples; !
!
Class CalculatorTest extends PHPUnit_Framework_TestCase !
{ !
public function testCalculatorCanAddByOne() !
{ !
$calculator = new Calculator(); !
$result = $calculator-addByOne(); !
$this-assertSame(1, $result); !
} !
}
10
11. My
autoloader
?php !
!
/** !
* Simple autoloader that follow the PHP Standards Recommendation #0 (PSR-0) !
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/
PSR-0.md for more informations. !
* !
* Code inspired from the SplClassLoader RFC !
* @see https://wiki.php.net/rfc/splclassloader#example_implementation !
*/ !
spl_autoload_register(function($className) { !
$className = ltrim($className, ''); !
$fileName = ''; !
$namespace = ''; !
if ($lastNsPos = strripos($className, '')) { !
$namespace = substr($className, 0, $lastNsPos); !
$className = substr($className, $lastNsPos + 1); !
$fileName = str_replace(!
'', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; !
} !
$fileName = __DIR__ . DIRECTORY_SEPARATOR . $fileName . $className . '.php'; !
if (file_exists($fileName)) { !
require $fileName; !
!
return true; !
} !
!
return false; !
});
11
14. A
lot
of
parameters!
• Easily
possible
to
make
mistakes
• Every
developer
might
use
different
params
• Not
easy
for
(semi-‐)automated
tes6ng
-‐
Using
IDE
for
running
unit
tests
13
15. Let’s
op6mise
this
?xml version=1.0 encoding=UTF-8?
!
!-- file: project/phpunit.xml --
!
phpunit bootstrap=./src/autoload.php colors=true
!
testsuite name=Unit Test Example code
directory./tests/directory
/testsuite
!
filter
whitelist
directory suffix=.php./src/directory
exclude
directory suffix=.phtml./src/directory
/exclude
/whitelist
/filter
!
/phpunit
14
23. Simple
Product
Model
Product
_productId : integer
_code : string
_title : string
_description : string
_image : string
_price : float
_created : DateTime
_modified : DateTime
__construct($params : null | array)
setProductId($productId : integer) : Product
getProductId() : integer
setCode($code : string) : Product
getCode() : string
setTitle($title : string) : Product
getTitle() : string
setDescription($description : string) : Product
getDescription() : string
setImage($image : string) : Product
getImage() : string
setPrice($price : float) : Product
getPrice() : float
setCreated($created : string | DateTime) : Product
getCreated() : DateTime
setModified($modified : string | DateTime) : Product
getModified() : DateTime
populate($data : array)
toArray() : array
__toString() : string
21
24. A
simple
ProductTest
?php !
namespace UtexamplesModel; !
/** !
* Class ProductTest !
* @package UtexamplesModel !
* @group Model !
*/ !
class ProductTest extends PHPUnit_Framework_TestCase !
{ !
public function testProductCanBePopulated() !
{ !
$data = array ( !
'productId' = 1, !
'code' = 'TSTPROD1', !
'title' = 'Test product 1', !
'description' = 'This is a full description of test product 1', !
'image' = 'image.png', !
'price' = 123.95, !
'created' = '2013-11-20 16:00:00', !
'modified' = '2013-11-20 17:00:00', !
); !
!
$product = new Product($data); !
$this-assertEquals($data, $product-toArray()); !
} !
}
22
25. A
simple
ProductTest
?php !
namespace UtexamplesModel; !
/** !
* Class ProductTest !
* @package UtexamplesModel !
* @group Model !
*/ !
class ProductTest extends PHPUnit_Framework_TestCase !
{ !
public function testProductCanBePopulated() !
{ !
$data = array ( !
'productId' = 1, !
'code' = 'TSTPROD1', !
'title' = 'Test product 1', !
'description' = 'This is a full description of test product 1', !
'image' = 'image.png', !
'price' = 123.95, !
'created' = '2013-11-20 16:00:00', !
'modified' = '2013-11-20 17:00:00', !
); !
!
$product = new Product($data); !
$product = new Product($data); !
$this-assertEquals($data, $product-toArray());
$this-assertEquals($data, $product-toArray()); !
} !
}
22
28. data
fixture
public function goodDataProvider() { !
return array ( !
array ( !
1, !
'TSTPROD1', !
'Test Product 1', !
'This is a full description of test product 1', !
'image.png', !
123.95, !
'2013-11-20 16:00:00', !
'2013-11-20 17:00:00', !
), !
array ( !
2, !
'TSTPROD2', !
'Test Product 2', !
'This is a full description of test product 2', !
'image.png', !
4125.99, !
'2013-11-20 16:00:00', !
'2013-11-20 17:00:00', !
), !
); !
}
24
29. Using
@dataProvider
/** !
* @dataProvider goodDataProvider !
*/ !
public function testProductCanBePopulated( !
$productId, $code, $title, $description, $image, $price, $created, $modified !
) !
{ !
$data = array ( !
'productId' = $productId, !
'code' = $code, !
'title' = $title, !
'description' = $description, !
'image' = $image, !
'price' = $price, !
'created' = $created, !
'modified' = $modified, !
); !
!
$product = new Product($data); !
$this-assertEquals($data, $product-toArray()); !
}
25
30. Using
@dataProvider
/** !
/** !
* @dataProvider goodDataProvider !
* @dataProvider goodDataProvider !
*/ !
*/
public function testProductCanBePopulated( !
$productId, $code, $title, $description, $image, $price, $created, $modified !
) !
{ !
$data = array ( !
'productId' = $productId, !
'code' = $code, !
'title' = $title, !
'description' = $description, !
'image' = $image, !
'price' = $price, !
'created' = $created, !
'modified' = $modified, !
); !
!
$product = new Product($data); !
$this-assertEquals($data, $product-toArray()); !
}
25
34. OWASP
top
10
exploits
https://www.owasp.org/index.php/Top_10_2013-Top_10
28
36. Libs
you
can
use
• Zend
Framework
1:
Zend_Filter_Input
• Zend
Framework
2:
ZendInputFilter
• Symfony:
SymfonyComponentValidator
• Aura:
AuraFrameworkInputFilter
• Lithium:
lithiumu6lValidator
• Laravel:
AppValidator
30
37. Modify
our
Product
class
?php !
namespace UtexamplesModel; !
!
class Product extends ModelAbstract !
{ !
...!
/** !
* @var Zend_Filter_Input The filter/validator for this Product !
*/ !
protected $_inputFilter; !
!
/** !
* @var bool The validation of data for this Product !
*/ !
protected $_valid; !
!
/** !
* Helper class to create filter and validation rules !
* !
* @access protected !
*/ !
protected function _createInputFilter() !
{ !
...!
} !
...!
}
31
38. _createInputFilter()
protected function _createInputFilter() !
{ !
$filters = array ( !
'productId' = array('Int'), !
'code' = array ('StripTags', 'StringTrim', 'StringToUpper'), !
'title' = array ('StripTags', 'StringTrim'), !
'description' = array ('StripTags', 'StringTrim'), !
'image' = array ('StripTags', 'StringTrim','StringToLower'), !
'price' = array (), !
); !
$validators = array ( !
'productId' = array ( !
'Int', !
array ('GreaterThan', array ('min' = 0, 'inclusive' = true)), !
), !
'code' = array ( !
'Alnum', !
array ('StringLength', array ('min' = 5, 'max' = 50)), !
), !
'title' = array ('NotEmpty'), !
'description' = array ('NotEmpty'), !
'image' = array ('NotEmpty'), !
'price' = array ( !
'Float', !
array ('GreaterThan', array ('min' = 0, 'inclusive' = true)), !
), !
); !
$this-_inputFilter = new Zend_Filter_Input($filters, $validators); !
}
32
39. Modify
your
seQers
/** !
* Set the product code for this Product !
* !
* @param string $code !
* @return Product !
*/ !
public function setCode($code) !
{ !
$this-_inputFilter-setData(array ('code' = $code)); !
if ($this-_inputFilter-isValid('code')) { !
$this-_code = $this-_inputFilter-code; !
$this-setValid(true); !
} else { !
$this-setValid(false); !
} !
return $this; !
}
33
40. Modify
your
seQers
/** !
* Set the product code for this Product !
* !
* @param string $code !
* @return Product !
*/ !
public function setCode($code) !
$this-_inputFilter-setData(array ('code' = $code));
{ !
if ($this-_inputFilter-isValid('code')) { !
$this-_inputFilter-setData(array ('code' = $code)); !
$this-_code = $this-_inputFilter-code; !
if ($this-_inputFilter-isValid('code')) { !
$this-_code = $this-_inputFilter-code; !
$this-setValid(true); !
$this-setValid(true); !
} else { !
} else { !
$this-setValid(false); !
$this-setValid(false); !
} ! !
}
return $this; !
return $this;
}
!
33
41. Using
dataproviders
again
public function badDataProvider() !
{ !
return array ( !
array ( !
1, '', '', '', '', 0, !
'0000-00-00 00:00:00', !
'0000-00-00 00:00:00', !
), !
array ( !
1, !
'!@#$%^@^*{}[]=-/'', 'Test Product 1', !
'This is a full description of test product 1', 'image.png', !
123.95, '2013-11-20 16:00:00', '2013-11-20 17:00:00', !
), !
array ( !
1, '' OR 1=1; --', 'Test Product 1', !
'This is a full description of test product 1', 'image.png', !
123.95, '2013-11-20 16:00:00', '2013-11-20 17:00:00', !
), !
); !
}
34
42. And
now
we
test
for
valid
data
/** !
* @dataProvider badDataProvider !
*/ !
public function testProductRejectsBadData( !
$productId, $code, $title, $description, $image, $price, $created, $modified !
) !
{ !
$data = array ( !
'productId' = $productId, !
'code' = $code, !
'title' = $title, !
'description' = $description, !
'image' = $image, !
'price' = $price, !
'created' = $created, !
'modified' = $modified, !
); !
!
$product = new Product($data); !
$this-assertFalse($product-isValid()); !
}
35
43. And
now
we
test
for
valid
data
/** !
* @dataProvider badDataProvider !
*/ !
public function testProductRejectsBadData( !
$productId, $code, $title, $description, $image, $price, $created, $modified !
) !
{ !
$data = array ( !
'productId' = $productId, !
'code' = $code, !
'title' = $title, !
'description' = $description, !
'image' = $image, !
'price' = $price, !
'created' = $created, !
'modified' = $modified, !
); !
!
$product = new Product($data); !
$product = new Product($data); !
$this-assertFalse($product-isValid()); !
$this-assertFalse($product-isValid());
}
35
47. 4
stages
of
database
tes6ng
• Setup
table
fixtures
• Run
tests
on
the
database
interac6ons
• Verify
results
of
tests
• Teardown
the
fixtures
38
49. Hello
DBUnit
?php !
namespace UtexamplesModel; !
!
use PHPUnit_Extensions_Database_DataSet_IDataSet; !
use PHPUnit_Extensions_Database_DB_IDatabaseConnection; !
use PHPUnit_Extensions_Database_DataSet_QueryDataSet; !
!
class ProductDbTest extends PHPUnit_Extensions_Database_TestCase !
{ !
protected $_pdo; !
!
public function __construct() !
{ !
$this-_pdo = new PDO('sqlite::memory:'); !
$this-_pdo-exec(!
file_get_contents(dirname(__DIR__) . ‘/../../data/schema.sqlite.sql')!
); !
} !
!
final public function getConnection() !
{ !
return $this-createDefaultDBConnection($this-_pdo, 'sqlite'); !
} !
!
protected function getDataSet() !
{ !
return $this-createFlatXMLDataSet(dirname(__DIR__) . '/_files/initialDataSet.xml'); !
} !
}
40
50. Hello
DBUnit
?php !
namespace UtexamplesModel; !
!
use PHPUnit_Extensions_Database_DataSet_IDataSet; !
use PHPUnit_Extensions_Database_DB_IDatabaseConnection; !
use PHPUnit_Extensions_Database_DataSet_QueryDataSet; !
!
class ProductDbTest extends PHPUnit_Extensions_Database_TestCase !
{ !
protected $_pdo; !
protected $_pdo; !
!
!
public function __construct()
!
{ !
public function __construct() !
$this-_pdo = new PDO('sqlite::memory:'); !
{ !
$this-_pdo-exec(!
$this-_pdo = new PDO('sqlite::memory:'); !
file_get_contents(dirname(__DIR__) . ‘/../../data/schema.sqlite.sql')!
$this-_pdo-exec(!
); !
} ! file_get_contents(dirname(__DIR__) . ‘/../../data/schema.sqlite.sql')!
!
); !
final public function getConnection() !
}
{ !
return $this-createDefaultDBConnection($this-_pdo, 'sqlite'); !
} !
!
protected function getDataSet() !
{ !
return $this-createFlatXMLDataSet(dirname(__DIR__) . '/_files/initialDataSet.xml'); !
} !
}
40
51. Hello
DBUnit
?php !
namespace UtexamplesModel; !
!
use PHPUnit_Extensions_Database_DataSet_IDataSet; !
use PHPUnit_Extensions_Database_DB_IDatabaseConnection; !
use PHPUnit_Extensions_Database_DataSet_QueryDataSet; !
!
class ProductDbTest extends PHPUnit_Extensions_Database_TestCase !
{ !
protected $_pdo; !
!
public function __construct() !
{ !
$this-_pdo = new PDO('sqlite::memory:'); !
$this-_pdo-exec(!
file_get_contents(dirname(__DIR__) . ‘/../../data/schema.sqlite.sql')!
); !
final public function getConnection() !
} !
{
!
!
return $this-createDefaultDBConnection($this-_pdo, 'sqlite'); !
final public function getConnection() !
{ !
}
return $this-createDefaultDBConnection($this-_pdo, 'sqlite'); !
} !
!
protected function getDataSet() !
{ !
return $this-createFlatXMLDataSet(dirname(__DIR__) . '/_files/initialDataSet.xml'); !
} !
}
40
52. Hello
DBUnit
?php !
namespace UtexamplesModel; !
!
use PHPUnit_Extensions_Database_DataSet_IDataSet; !
use PHPUnit_Extensions_Database_DB_IDatabaseConnection; !
use PHPUnit_Extensions_Database_DataSet_QueryDataSet; !
!
class ProductDbTest extends PHPUnit_Extensions_Database_TestCase !
{ !
protected $_pdo; !
!
public function __construct() !
{ !
$this-_pdo = new PDO('sqlite::memory:'); !
$this-_pdo-exec(!
file_get_contents(dirname(__DIR__) . ‘/../../data/schema.sqlite.sql')!
); !
} !
!
final public function getConnection() !
{ !
protected function getDataSet() !
return $this-createDefaultDBConnection($this-_pdo, 'sqlite'); !
{ !
} !
return $this-createFlatXMLDataSet(!
!
dirname(__DIR__) . ‘/_files/initialDataSet.xml'!
protected function getDataSet() !
{); !
!
return $this-createFlatXMLDataSet(dirname(__DIR__) . '/_files/initialDataSet.xml'); !
}
} !
}
40
53. Hello
DBUnit
?php !
namespace UtexamplesModel; !
!
use PHPUnit_Extensions_Database_DataSet_IDataSet; !
use PHPUnit_Extensions_Database_DB_IDatabaseConnection; !
use PHPUnit_Extensions_Database_DataSet_QueryDataSet; !
!
class ProductDbTest extends PHPUnit_Extensions_Database_TestCase !
{ !
protected $_pdo; !
!
public function __construct() !
{ !
$this-_pdo = new PDO('sqlite::memory:'); !
$this-_pdo-exec(!
file_get_contents(dirname(__DIR__) . ‘/../../data/schema.sqlite.sql')!
); !
} !
!
final public function getConnection() !
{ !
protected function getDataSet() !
return $this-createDefaultDBConnection($this-_pdo, 'sqlite'); !
{ !
} !
return $this-createFlatXMLDataSet(!
!
dirname(__DIR__) . ‘/_files/initialDataSet.xml'!
protected function getDataSet() !
{); !
!
return $this-createFlatXMLDataSet(dirname(__DIR__) . '/_files/initialDataSet.xml'); !
}
} !
}
40
54. Ini6alDataset
?xml version=1.0 encoding=UTF-8?
dataset
product
productId=1
code=TEST CODE1
title=First test product
description=This is our first test product
image=http://www.example.com/image/image.png
price=150.95
created=2013-03-30 10:11:12
modified=2013-12-11 09:08:07/
product
productId=2
code=TEST CODE2
title=Second test product
description=This is our second test product
image=http://www.example.com/image/image.png
price=19999.00
created=2013-03-30 10:11:12
modified=2013-12-11 09:08:07/
product
productId=3
code=TEST CODE3
title=Third test product
description=This is our third test product
image=http://www.example.com/image/image.png
price=0.45
created=2013-03-30 10:11:12
modified=2013-12-11 09:08:07/
/dataset
41
56. Adding
Data
Test
public function testProductAddToDatabase() !
{ !
$data = array ( !
'code' = 'TST', !
'title' = 'Test', !
'description' = 'Testing Test', !
'image' = 'http://www.example.com/image.png', !
'price' = 10.00, !
'created' = '2013-12-15 01:55:00', !
'modified' = '2013-12-20 16:00:00', !
); !
!
$product = new Product($data); !
$product-setPdo($this-_pdo); !
$product-save(); !
!
$expectedDs = $this-createFlatXMLDataSet( !
dirname(__DIR__) . '/_files/addProductDataSet.xml' !
); !
$currentDs = $this-getConnection()-createDataSet(array ('product')); !
$this-assertDataSetsEqual($expectedDs, $currentDs); !
}
43
68. Some
downsides
• Tes6ng
databases
takes
6me
-‐
-‐
-‐
-‐
-‐
create
a
real
database
connec6on
reini6alise
the
database
(load
schema,
truncate
tables)
load
ini6al
state
before
test
(with
each
test)
execute
on
the
database
compare
expected
result
with
actual
result
51
70. Mock
objects
• They
replace
an
object
for
tes6ng
-‐
-‐
a
class
with
all
methods
a
class
with
a
single
method
-‐
-‐
-‐
databases
web
services
file
systems
-‐
once
you
got
everything
set
up
• Since
they
replace
“expansive”
connec6ons
• Are
quicker
and
more
reliable
to
test
53
71. Same
tests,
but
now
mocked
?php !
!
namespace UtexamplesModel; !
!
use PDO; !
use PDOStatement; !
!
class ProductMockTest extends PHPUnit_Framework_TestCase !
{ !
public function testProductsCanBeLoadedFromDatabase() !
{ !
!
} !
!
public function testProductAddToDatabase() !
{ !
!
} !
}
54
72. testProductsCanBeLoadedFromDatabase
public function testProductsCanBeLoadedFromDatabase() !
{ !
$data = array (); !
// let's mock the prepare statement !
$pdostmt = $this-getMock('PDOStatement', array ('execute', 'fetchAll')); !
$pdostmt-expects($this-atLeastOnce()) !
-method('execute') !
-will($this-returnValue(true)); !
$pdostmt-expects($this-atLeastOnce()) !
-method('fetchAll') !
-will($this-returnValue($data)); !
// let's mock the PDO object and return the mocked statement !
$pdo = $this-getMock('PDO', array ('prepare'), array ('sqlite::memory')); !
$pdo-expects($this-atLeastOnce()) !
-method('prepare') !
-will($this-returnValue($pdostmt)); !
!
$productCollection = new ProductCollection(); !
$productCollection-setPdo($pdo); !
$productCollection-fetchAll(); !
!
$this-assertEquals($data, $productCollection-toArray()); !
}
55
73. My
$data
array
$data = array ( !
array ( !
'productId' = 1, !
'code' = 'TST1', !
'title' = 'Test 1', !
'description' = 'Testing product 1', !
'image' = 'http://www.example.com/image1.png', !
'price' = 10.00, !
'created' = '2013-12-01 01:55:00', !
'modified' = '2013-12-20 16:00:00', !
), !
array ( !
'productId' = 2, !
'code' = 'TST2', !
'title' = 'Test 2', !
'description' = 'Testing product 2', !
'image' = 'http://www.example.com/image2.png', !
'price' = 199.95, !
'created' = '2013-12-02 02:55:00', !
'modified' = '2013-12-20 16:00:00', !
), !
);
56
74. testProductAddToDatabase
public function testProductAddToDatabase() !
{ !
$pdostmt = $this-getMock('PDOStatement', array ('execute')); !
$pdostmt-expects($this-atLeastOnce()) !
-method('execute') !
-will($this-returnValue(true));!
$pdo = $this-getMock('PDO', array ('prepare'), array ('sqlite::memory')); !
$pdo-expects($this-once()) !
-method('prepare') !
-will($this-returnValue($pdostmt)); !
!
$data = array ( !
'code' = 'TST', !
'title' = 'Test', !
'description' = 'Testing Test', !
'image' = 'http://www.example.com/image.png', !
'price' = 10.00, !
'created' = '2013-12-15 01:55:00', !
'modified' = '2013-12-20 16:00:00', !
); !
$product = new Product($data); !
$product-setPdo($pdo); !
$product-save(); !
!
// The model has mentioning of productId !
$data['productId'] = null; !
$this-assertEquals($data, $product-toArray()); !
}
57
77. Why
the
extra
work?
• Your
databases
are
fully
tested,
no
need
to
do
it
yourself
again
• The
connec6ons
are
expensive
and
delay
your
tests
• Your
tes6ng
code
that
needs
to
handle
the
data
it
gets,
no
maQer
where
it
gets
it
59
82. Joindin
Test
?php !
class Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase !
{ !
protected $_joindin; !
protected $_settings; !
!
protected function setUp() !
{ !
$this-_joindin = new Zftest_Service_Joindin(); !
$settings = simplexml_load_file(realpath( !
APPLICATION_PATH . '/../tests/_files/settings.xml')); !
$this-_settings = $settings-joindin; !
parent::setUp(); !
} !
protected function tearDown() !
{ !
parent::tearDown(); !
$this-_joindin = null; !
} !
}
64
83. Joindin
Test
(2)
public function testJoindinCanGetUserDetails() !
{ !
$expected = '?xml version=1.0?responseitemusernameDragonBe/
usernamefull_nameMichelangelo van Dam/full_nameID19/IDlast_login1303248639/
last_login/item/response'; !
$this-_joindin-setUsername($this-_settings-username) !
-setPassword($this-_settings-password); !
$actual = $this-_joindin-user()-getDetail(); !
$this-assertXmlStringEqualsXmlString($expected, $actual); !
} !
!
public function testJoindinCanCheckStatus() !
{ !
$date = new DateTime(); !
$date-setTimezone(new DateTimeZone('UTC')); !
$expected = '?xml version=1.0?responsedt' . $date-format('r') . '/
dttest_stringtesting unit test/test_string/response'; !
$actual = $this-_joindin-site()-getStatus('testing unit test'); !
$this-assertXmlStringEqualsXmlString($expected, $actual); !
}
65
86. Euh…
what
just
happened?
1) Zftest_Service_JoindinTest::testJoindinCanGetUserDetails
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
ID19/ID
last_login1303248639/last_login
+
last_login1303250271/last_login
/item
/response
67
89. Let’s
mock
the
HTTP
client
?php !
class Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase !
{ !
protected $_joindin; !
protected $_settings; !
!
protected function setUp() !
{ !
$this-_joindin = new Zftest_Service_Joindin(); !
$client = new Zend_Http_Client(); !
$client-setAdapter(new Zend_Http_Client_Adapter_Test()); !
$this-_joindin-setClient($client); !
$settings = simplexml_load_file(realpath( !
APPLICATION_PATH . '/../tests/_files/settings.xml')); !
$this-_settings = $settings-joindin; !
parent::setUp(); !
} !
protected function tearDown() !
{ !
parent::tearDown(); !
$this-_joindin = null; !
} !
}
70
90. Let’s
mock
the
HTTP
client
?php !
class Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase !
{ !
protected $_joindin; !
protected $_settings; !
!
protected function setUp() !
{ !
$this-_joindin = new Zftest_Service_Joindin(); !
$client = new Zend_Http_Client(); !
$client-setAdapter(new Zend_Http_Client_Adapter_Test());
$client-setAdapter(new Zend_Http_Client_Adapter_Test()); !
$this-_joindin-setClient($client); !
$this-_joindin-setClient($client); !
$settings = simplexml_load_file(realpath( !
$settings = simplexml_load_file(realpath( !
APPLICATION_PATH . '/../tests/_files/settings.xml')); !
APPLICATION_PATH . '/../tests/_files/settings.xml'));
$this-_settings = $settings-joindin; !
parent::setUp(); !
} !
protected function tearDown() !
{ !
parent::tearDown(); !
$this-_joindin = null; !
} !
}
!
70
91. Mocking
the
response
public function testJoindinCanGetUserDetails() !
{ !
$response = EOS !
HTTP/1.1 200 OK !
Content-type: text/xml !
!
?xml version=1.0? !
response !
item !
usernameDragonBe/username !
full_nameMichelangelo van Dam/full_name !
ID19/ID !
last_login1303248639/last_login !
/item !
/response !
EOS; !
$client = $this-_joindin-getClient()-getAdapter()-setResponse($response); !
$expected = '?xml version=1.0?responseitemusernameDragonBe/
usernamefull_nameMichelangelo van Dam/full_nameID19/IDlast_login1303248639/
last_login/item/response'; !
$this-_joindin-setUsername($this-_settings-username) !
-setPassword($this-_settings-password); !
$actual = $this-_joindin-user()-getDetail(); !
$this-assertXmlStringEqualsXmlString($expected, $actual); !
}
71
92. Mocking
the
response
public function testJoindinCanGetUserDetails() !
{ !
$response = EOS !
HTTP/1.1 200 OK !
Content-type: text/xml !
!
?xml version=1.0? !
response !
item !
usernameDragonBe/username !
full_nameMichelangelo van Dam/full_name !
ID19/ID !
last_login1303248639/last_login !
/item !
/response !
EOS; !
$client = $this-_joindin-getClient()-getAdapter()-setResponse($response);
$client = $this-_joindin-getClient()-getAdapter()-setResponse($response); !
$expected = '?xml version=1.0?responseitemusernameDragonBe/
usernamefull_nameMichelangelo van Dam/full_nameID19/IDlast_login1303248639/
last_login/item/response'; !
$this-_joindin-setUsername($this-_settings-username) !
-setPassword($this-_settings-password); !
$actual = $this-_joindin-user()-getDetail(); !
$this-assertXmlStringEqualsXmlString($expected, $actual); !
}
71
93. Same
here
public function testJoindinCanCheckStatus() !
{ !
$date = new DateTime(); !
$date-setTimezone(new DateTimeZone('UTC')); !
$response = EOS !
HTTP/1.1 200 OK !
Content-type: text/xml !
!
?xml version=1.0? !
response !
dt{$date-format('r')}/dt !
test_stringtesting unit test/test_string !
/response !
EOS; !
!
$client = $this-_joindin-getClient() !
-getAdapter()-setResponse($response);!
!
$expected = '?xml version=1.0?responsedt' . $date-format('r') . '/
dttest_stringtesting unit test/test_string/response'; !
$actual = $this-_joindin-site()-getStatus('testing unit test'); !
$this-assertXmlStringEqualsXmlString($expected, $actual); !
}
72
94. Same
here
public function testJoindinCanCheckStatus() !
{ !
$date = new DateTime(); !
$date-setTimezone(new DateTimeZone('UTC')); !
$response = EOS !
HTTP/1.1 200 OK !
Content-type: text/xml !
!
?xml version=1.0? !
response !
dt{$date-format('r')}/dt !
test_stringtesting unit test/test_string !
/response !
EOS; !
!
$client = $this-_joindin-getClient() !
$client = $this-_joindin-getClient() !
-getAdapter()-setResponse($response);
-getAdapter()-setResponse($response);!
!
$expected = '?xml version=1.0?responsedt' . $date-format('r') . '/
dttest_stringtesting unit test/test_string/response'; !
$actual = $this-_joindin-site()-getStatus('testing unit test'); !
$this-assertXmlStringEqualsXmlString($expected, $actual); !
}
72
105. Michelangelo van Dam
Zend Certified Engineer
!
michelangelo@in2it.be
PHP Consulting - QA audits - Training
!
www.in2it.be
82
106. Credits
• Me:
hQp://www.flickr.com/photos/akrabat/8784318813
• CrashTest:
hQp://www.flickr.com/photos/digi6zedchaos/3964206549
• Chris:
hQp://www.flickr.com/photos/akrabat/8421560178
• Nike:
hQp://www.flickr.com/photos/japokskee/4393860599
• Grads:
hQp://www.flickr.com/photos/ajschwegler/525829339
• Econopoly:
hQp://www.flickr.com/photos/danielbroche/2258988806
• Disaster:
hQp://www.flickr.com/photos/eschipul/1484495808/
• Mountain:
hQp://www.flickr.com/photos/jfdervin/2510535266
• Data
Store:
hQp://www.flickr.com/photos/comedynose/7048321621
• Protect:
hQp://www.flickr.com/photos/boltowlue/5724934828
• Owl:
hQp://www.flickr.com/photos/15016964@N02/9425608812
• Register:
hQp://www.flickr.com/photos/taedc/5466788868
• Crying
Baby:
hQp://www.flickr.com/photos/bibbit/5456802728
• Smiling
Donkey:
hQp://www.flickr.com/photos/smkybear/2239030703
• Jump
high:
hQp://www.flickr.com/photos/96748294@N06/9356699040
• Chipmunk:
hQp://www.flickr.com/photos/exfordy/1184487050
• Easy:
hQp://www.flickr.com/photos/dalismustaches/223972376
• Spaghen:
hQp://www.flickr.com/photos/lablasco/5512066970
• BaQery:
hQp://www.flickr.com/photos/shalf/6088539194
• Elephpant:
hQp://www.flickr.com/photos/dragonbe/11403208686
83