unit testing
DESCRIPTION
unit testing in PHP with PHPUnitTRANSCRIPT
![Page 1: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/1.jpg)
Unit TestingBy David Haskins
![Page 2: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/2.jpg)
bool underAttack = false;
underAttack = detectEvents();
//do some other stuff
if(underAttack = true) {launchNuclearMissles();
} else {alert(“false alarm!”);
}
![Page 3: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/3.jpg)
Why Test?
• Sometimes we make mistakes in our code
![Page 4: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/4.jpg)
Why Test?
• Sometimes we make mistakes in our code
• Sometimes we forget to finish parts of our code because we get interrupted, and then we never come back and finish
![Page 5: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/5.jpg)
Why Test?
• Sometimes we make mistakes in our code
• Sometimes we forget to finish parts of our code because we get interrupted, and then we never come back and finish
• //TODO: add another reason
![Page 6: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/6.jpg)
Testing vs. Debugging
Testing: detecting errors
Debugging: diagnose and repair detected errors
![Page 7: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/7.jpg)
Types of testing
regression tests
functional tests
acceptance tests
integration tests
load/stress tests
security tests
unit tests
![Page 8: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/8.jpg)
Unit Testing
Unit Testing: the execution of [code] that has been written by a single programmer or team of programmers, which is tested in isolation from the more complete system.
- Code Complete 2nd ed.
![Page 9: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/9.jpg)
How we end up testing stuff
class User{
public function __construct($userName){
//do stuff
}
public function checkPassword($password){
//do stuff
}
public function setLogIn(){
//do stuff
}
}
![Page 10: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/10.jpg)
How we end up testing stuff
$u = new User(‘[email protected]’);
//test to fail
$u->checkPassword(‘bad_password’);
//test to succeed
$u->checkPassword(‘s3kr3t_p@sswd’);
![Page 11: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/11.jpg)
How we end up testing stuff
$u = new User(‘[email protected]’);
//test to fail
if($u->checkPassword(‘bad_password’) === false){
echo ‘successfully rejected’;
}
//test to succeed
if($u->checkPassword(‘s3kr3t_p@sswd’) === true){
echo ‘successfully accepted’;
}
![Page 12: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/12.jpg)
What do we do with this information?
![Page 13: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/13.jpg)
What do we do with this information?
We delete it!!!
![Page 14: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/14.jpg)
What do we do with this information?
We delete it!!!
(or, at best, we comment it out)
![Page 15: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/15.jpg)
![Page 16: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/16.jpg)
PHPUnit
• a framework for unit testing PHP
• excellent documentation at http://phpunit.de
• easy to setup
![Page 17: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/17.jpg)
Installing PHPUnit
• Pear
• Composer (preferred method)
![Page 18: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/18.jpg)
Installing PHPUnit
pear config-set audto_discover 1
pear install pear.phpunit.de/PHPUnit
![Page 19: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/19.jpg)
Installing PHPUnit
Composer can be used to download and install “dependencies”(other libraries and such).
download composer:
curl -s http://getcomposer.org/installer | php
![Page 20: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/20.jpg)
Installing PHPUnit
create a file named composer.json containing:
{
“require-dev”: {
“phpunit/phpunit”: “3.7.4”
}
}
![Page 21: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/21.jpg)
Installing PHPUnit
run:
./composer.phar update
(a .phar file is a “PHP Archive” file.)
![Page 22: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/22.jpg)
Installing PHPUnit
create a file named phpunit.xml containing:
<?xml version="1.0" encoding="UTF-8"?><phpunit colors="true"> <testsuites> <testsuite name="Application Test Suite"> <directory>./phpUnitTutorial/Test/</directory> </testsuite> </testsuites></phpunit>
![Page 23: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/23.jpg)
Running PHPUnit
./vendor/bin/phpunit
![Page 24: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/24.jpg)
Running PHPUnit
./vendor/bin/phpunit
![Page 25: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/25.jpg)
A simple PHPUnit test
![Page 26: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/26.jpg)
class myTest extends PHPUnitTest_Framework_TestCase {
}
![Page 27: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/27.jpg)
class myTest extends PHPUnitTest_Framework_TestCase {
public function someSimpleTest(){
}
}
![Page 28: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/28.jpg)
class myTest extends PHPUnitTest_Framework_TestCase {
public function someSimpleTest(){
$myVar = true;
$this->assertTrue($myVar);
}
}
![Page 29: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/29.jpg)
class myTest extends PHPUnitTest_Framework_TestCase {
public function someSimpleTest(){
$myVar = true;
$this->assertTrue($myVar);
}
public function anotherSimpleTest(){
$myVar = false;
$this->assertTrue($myvar); //fails
}
}
![Page 30: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/30.jpg)
PHPUnit offers:
assertTrue();
assertFalse();
assertEquals();
assertArrayHasKey();
assertStringEndsWith();
...and many more!
![Page 31: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/31.jpg)
The next few examples are
from Juan Treminio’s tutorial:
https://jtreminio.com/2013/03
![Page 32: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/32.jpg)
The phrase “slugify” means to change
something like this:
The quick BROWN fox @ noon
into this:
the-quick-brown-fox-noon
![Page 33: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/33.jpg)
<?phpclass URL{ public function sluggify($string, $separator = '-', $maxLength = 96) { $title = iconv('UTF-8', 'ASCII//TRANSLIT', $string); $title = preg_replace("%[^-/+|\w ]%", '', $title); $title = strtolower(trim(substr($title, 0, $maxLength), '-')); $title = preg_replace("/[\/_|+ -]+/", $separator, $title);
return $title; }
}
![Page 34: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/34.jpg)
Let’s write a test for it!
![Page 35: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/35.jpg)
namespace phpUnitTutorial\Test;use phpUnitTutorial\URL;class URLTest extends \PHPUnit_Framework_TestCase{
}
![Page 36: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/36.jpg)
namespace phpUnitTutorial\Test;use phpUnitTutorial\URL;class URLTest extends \PHPUnit_Framework_TestCase{ public function testSluggifyReturnsSluggifiedString() { $originalString = 'This string will be sluggified'; $expectedResult = 'this-string-will-be-sluggified';
}
}
![Page 37: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/37.jpg)
namespace phpUnitTutorial\Test;use phpUnitTutorial\URL;class URLTest extends \PHPUnit_Framework_TestCase{ public function testSluggifyReturnsSluggifiedString() { $originalString = 'This string will be sluggified'; $expectedResult = 'this-string-will-be-sluggified';
$url = new URL();
$result = $url->sluggify($originalString);
}
}
![Page 38: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/38.jpg)
namespace phpUnitTutorial\Test;use phpUnitTutorial\URL;class URLTest extends \PHPUnit_Framework_TestCase{ public function testSluggifyReturnsSluggifiedString() { $originalString = 'This string will be sluggified'; $expectedResult = 'this-string-will-be-sluggified';
$url = new URL();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result); }
}
![Page 39: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/39.jpg)
We have a unit test!
{run example}
![Page 40: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/40.jpg)
Other tests we can add
public function testSluggifyReturnsExpectedForStringsContainingNumbers() { $originalString = 'This1 string2 will3 be 44 sluggified10'; $expectedResult = 'this1-string2-will3-be-44-sluggified10';
$url = new URL();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result); }
![Page 41: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/41.jpg)
Other tests we can add
public function testSluggifyReturnsExpectedForStringsContainingSpecialCharacters() { $originalString = 'This! @string#$ %$will ()be "sluggified'; $expectedResult = 'this-string-will-be-sluggified';
$url = new URL();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result); }
![Page 42: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/42.jpg)
Other tests we can add
public function testSluggifyReturnsExpectedForStringsContainingNonEnglishCharacters() { $originalString = "Tänk efter nu – förr'n vi föser dig bort"; $expectedResult = 'tank-efter-nu-forrn-vi-foser-dig-bort';
$url = new URL();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result); }
![Page 43: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/43.jpg)
Other tests we can add
public function testSluggifyReturnsExpectedForEmptyStrings() { $originalString = ''; $expectedResult = '';
$url = new URL();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result); }
![Page 44: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/44.jpg)
{run example without comments}
![Page 45: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/45.jpg)
That’s neat, but it seems we are writing the same code over and over.
![Page 46: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/46.jpg)
That’s neat, but it seems we are writing the same code over and over.
We can use the “dataProvider annotation.”
![Page 47: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/47.jpg)
That’s neat, but it seems we are writing the same code over and over.
We can use the “dataProvider annotation.”
Annotations are described in docblocks (comments) of methods.
![Page 48: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/48.jpg)
class URLTest extends \PHPUnit_Framework_TestCase{ /** * @dataProvider providerTestSluggifyReturnsSluggifiedString */ public function testSluggifyReturnsSluggifiedString($originalString, $expectedResult) {
//do our assertion here }
public function providerTestSluggifyReturnsSluggifiedString() {
//return an array of arrays which contains our data }}
![Page 49: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/49.jpg)
class URLTest extends \PHPUnit_Framework_TestCase{ /** * @dataProvider providerTestSluggifyReturnsSluggifiedString */ public function testSluggifyReturnsSluggifiedString($originalString, $expectedResult) { $url = new URL();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result); }
public function providerTestSluggifyReturnsSluggifiedString() { return array( array('This string will be sluggified', 'this-string-will-be-sluggified'), array('THIS STRING WILL BE SLUGGIFIED', 'this-string-will-be-sluggified'), array('This1 string2 will3 be 44 sluggified10', 'this1-string2-will3-be-44-sluggified10'), array('This! @string#$ %$will ()be "sluggified', 'this-string-will-be-sluggified'), array("Tänk efter nu – förr'n vi föser dig bort", 'tank-efter-nu-forrn-vi-foser-dig-bort'), array('', ''), ); }}
![Page 50: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/50.jpg)
I haven’t been honest here
URL::Sluggify() was deceptively simple it; had no dependencies.
![Page 51: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/51.jpg)
When you're doing testing like this, you're focusing on one element of the software at a time -hence the common term unit testing. The problem is that to make a single unit work, you often need other units...
- Martin Fowlerhttp://martinfowler.com/articles/mocksArentStubs.html
![Page 52: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/52.jpg)
What happens when we depend on other stuff (databases, other objects, etc.)?
![Page 53: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/53.jpg)
setUp() and tearDown()
class FoobarTest extends PHPUnit_Framework_Testcase{
public function setUp(){
//do things before these tests run
// copy a production database into a test db
// instantiate objects
// define constants
}
public function tearDown(){
//do things after the tests run
// delete test db
}
}
![Page 54: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/54.jpg)
But we still have problems
Databases can go down which could cause our tests to fail.
Instantiating objects can be slow which could make testing take forever (we want to be able to test often).
...and we want isolation!
![Page 55: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/55.jpg)
“Mocks and stubs” to the rescue!
![Page 56: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/56.jpg)
We may have to jump through some hoops, but we’ll get there!
![Page 57: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/57.jpg)
Stubs//a method with stuff (implementation details irrelevant)
public function doSomething($param1, $param2){
mysql_connect("your.hostaddress.com", $param1, $param2) or
die(mysql_error());
mysql_select_db("address") or die(mysql_error());
!(isset($pagenum)) ? $pagenum = 1 : $pagenum=0;
$data = mysql_query("SELECT * FROM topsites") or die(mysql_error());
$rows = mysql_num_rows($data);
$page_rows = 4;
$last = ceil($rows/$page_rows);
$pagenum < 1 ? $pagenum=1 : $pagenum = $last;
$max = 'limit ' .($pagenum - 1) * $page_rows .',' .$page_rows;
return $max;
}
![Page 58: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/58.jpg)
Stubs//a method with stuff (implementation details irrelevant)
public function StubDoSomething($param1, $param2){
return null;
}
![Page 59: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/59.jpg)
Mock objects
Mock Objects: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
![Page 60: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/60.jpg)
Mock objects
Let’s look at an example.
![Page 61: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/61.jpg)
Mock objectsclass User{
public function __construct($id){
$this-> id = $id;
}
public function verifyUser(){
//validate against an LDAP server
}
public function getName(){
//get user name from the LDAP server
}
}
![Page 62: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/62.jpg)
Mock objectsclass ForumPost{
public function deletePostsByUser($user){
$user_id = $user->getUserID();
$query = “delete from posts where userID = ? ”;
….//do stuff
}
//...other methods
}
![Page 63: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/63.jpg)
require_once ‘User.php’;
require_once ‘ForumPost.php’;
class testForum extends PHPUnitTest_Framework_TestCase {
public function testUserPostDelete(){
$user = new User(7);
$userName = $user->getName();
$post = new ForumPost();
$rowsDeleted = $post->deletePostsByUser($user);
$message = “$rowsDeleted posts removed for $userName”;
$expectedMessage = “5 posts removed for David Haskins”;
$this->assertEquals($message,$expectedMessage);
}
}
![Page 64: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/64.jpg)
require_once ‘User.php’;
require_once ‘ForumPost.php’;
class testForum extends PHPUnitTest_Framework_TestCase {
public function testUserPostDelete(){
$user = new User(7); //fails when LDAP server is down!
$userName = $user->getName();
$post = new ForumPost();
$rowsDeleted = $post->deletePostsByUser($user);
$message = “$rowsDeleted posts removed for $userName”;
$expectedMessage = “5 posts removed for David Haskins”;
$this->assertEquals($message,$expectedMessage);
}
}
![Page 65: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/65.jpg)
require_once ‘User.php’;
require_once ‘ForumPost.php’;
class testForum extends PHPUnitTest_Framework_TestCase {
public function testUserPostDelete(){
$user = $this->getMockBuilder(‘User’)
->setConstructorArgs(array(7))
->getMock();
$user->expects($this->once())
->method(‘getName’)
->will($this->returnValue(‘David Haskins’);
$userName = $user->getName();
$post = new ForumPost();
$rowsDeleted = $post->deletePostsByUser($user);
$message = “$rowsDeleted posts removed for $userName”;
$expectedMessage = “5 posts removed for David Haskins”;
$this->assertEquals($message,$expectedMessage);
}
}
![Page 66: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/66.jpg)
![Page 67: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/67.jpg)
TDD
Test Driven Development is a method of developing code by writing the tests FIRST!
![Page 68: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/68.jpg)
TDD
![Page 69: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/69.jpg)
Git and unit tests
You can add client or server side “hooks” to git to run your unit tests and reject submissions that fail the unit tests.
http://www.masnun.com/2012/03/18/running-phpunit-on-git-hook.html
![Page 70: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/70.jpg)
Coverage report tool
./vendor/bin/phpunit --coverage-html coverage
![Page 71: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/71.jpg)
bool underAttack = false;
underAttack = detectEvents();
//do some other stuff
if(underAttack = true) {launchNuclearMissles();
} else {alert(“false alarm!”);
}
![Page 72: Unit testing](https://reader036.vdocument.in/reader036/viewer/2022081519/55580ed7d8b42ae31c8b54eb/html5/thumbnails/72.jpg)
Other Texts to Consider
https://jtreminio.com/2013/03
http://phpunit.de