SlideShare a Scribd company logo
Unit Testing from
Setup to Deployment
Mark Niebergall
Thank You!
• Entrata - Venue, Food

• JetBrains - 1 free license

• Platform.sh - Zoom
https://analyze.co.za/wp-content/uploads/2018/12/441-1170x500.jpg
Objective
• Be familiar with how to setup PHPUnit

• Familiar with how to test existing code

• Know how to write unit tests using PHPUnit with
Prophecy

• Convince team and management to leverage automated
testing
Overview
• Bene
fi
ts of Unit Testing

• PHPUnit Setup

• Writing Unit Tests

• Testing Existing Code
Bene
fi
ts of Unit Testing
Bene
fi
ts of Unit Testing
public static function add($a, $b)
{
return $a + $b;
}
Bene
fi
ts of Unit Testing
public static function add($a, $b)
{
return $a + $b;
}
public function add(float ...$numbers): float
{
$return = 0;
foreach ($numbers as $value) {
$return = bcadd(
(string) $return,
(string) $value,
10
);
}
return (float) $return;
}
Bene
fi
ts of Unit Testing
http://www.ambysoft.com/artwork/comparingTechniques.jpg
Bene
fi
ts of Unit Testing
• Automated way to test code

- Regression Testing
Bene
fi
ts of Unit Testing
• Automated way to test code

- Continuous Integration

- Continuous Deployment
Bene
fi
ts of Unit Testing
• Automated way to test code

- Other ways to automatically test code beside functional
tests

‣ Behavioral tests (behat)

‣ phpspec (functional)

‣ Selenium (browser automation)

‣ Others?
Bene
fi
ts of Unit Testing
• Decrease bugs introduced with code

- Decreased time to deployment

- Better use of QA team time
Bene
fi
ts of Unit Testing
• Decrease bugs introduced with code

- High con
fi
dence in delivered code
Bene
fi
ts of Unit Testing
• Con
fi
dence when refactoring

- Tests covering code being refactored

- TDD

‣ Change tests

‣ Tests fail

‣ Change code

‣ Tests pass
PHPUnit Setup
PHPUnit Setup
• Install via composer

• Setup `phpunit.xml` for con
fi
guration (if needed)

• Run unit tests
PHPUnit Setup
• phpunit/phpunit

• phpspec/prophecy-phpunit

• fakerphp/faker
PHPUnit Setup
composer require --dev phpunit/phpunit
composer require --dev phpspec/prophecy-phpunit
composer require --dev fakerphp/faker
PHPUnit Setup
• File phpunit.xml

- PHPUnit con
fi
guration for that project

- Documentation: https://phpunit.readthedocs.io/en/9.5/
con
fi
guration.html



<?xml version="1.0" encoding="UTF-8"?>

<phpunit colors="true"
verbose="true"
bootstrap="./tests/Bootstrap.php">
<testsuite name="All Tests">
<directory>./tests</directory>
</testsuite>
</phpunit>
PHPUnit Setup
• Running PHPUnit



vendor/bin/phpunit tests/
PHPUnit 9.5.6 by Sebastian Bergmann and contributors.
Runtime: PHP 8.0.8
Con
fi
guration: /Users/mniebergall/projects/training/phpunit/
phpunit.xml
......... 9 / 9 (100%)
Time: 00:00.032, Memory: 6.00 MB
OK (9 tests, 12 assertions)
PHPUnit Setup
• Running PHPUnit

- Within PhpStorm
PHPUnit Setup
• Directory Structure

- PHP
fi
les in src/

‣ Ex: src/Math/Adder.php

- tests in tests/src/, ‘Test’ at end of
fi
lename

‣ Ex: tests/src/Math/AdderTest.php
Writing Unit Tests
Writing Unit Tests
public function add(float ...$numbers): float
{
$return = 0;
foreach ($numbers as $value) {
$return = bcadd(
(string) $return,
(string) $value,
10
);
}
return (float) $return;
}
Writing Unit Tests
use PHPUnitFrameworkTestCase;
class AdderTest extends TestCase
{
protected Adder $adder;
public function setUp(): void
{
$this->adder = new Adder();
}
public function testAdderWithSetup()
{
$sum = $this->adder->add(3, 7);
$this->assertSame(10.0, $sum);
}
Writing Unit Tests
public function testAdderThrowsExceptionWhenNotANumber()
{
$this->expectException(TypeError::class);
$adder = new Adder();
$adder->add(7, 'Can't add this');
}
Writing Unit Tests
public function testAdderAddsIntegers()
{
$adder = new Adder();
$sum = $adder->add(7, 3, 5, 5, 6, 4, 1, 9);
$this->assertSame(40.0, $sum);
}
public function testAdderAddsDecimals()
{
$adder = new Adder();
$sum = $adder->add(1.5, 0.5);
$this->assertSame(2.0, $sum);
}
Writing Unit Tests
/**
* @dataProvider dataProviderNumbers
*/
public function testAdderAddsNumbers(
float $expectedSum,
...$numbers
) {
$adder = new Adder();
$sum = $adder->add(...$numbers);
$this->assertSame($expectedSum, $sum);
}
public function dataProviderNumbers(): array
{
return [
[2, 1, 1],
[2, 1.5, 0.5],
];
}
Writing Unit Tests
• Test Coverage

- Percent of code covered by tests

- Not aiming for 100%

- No need to test language constructs
Writing Unit Tests
• Code should be self-contained

- No actual database connections

- No API calls should occur

- No external code should be called

‣ Use testing framework
Writing Unit Tests
• Assertions

$this->assertInstanceOf(Response::class, $response);
$this->assertEquals(200, $response->getStatusCode());
$this->assertSame(401, $responseActual->getStatusCode());
$this->assertTrue($dispatched);
$this->assertFalse($sent);
Writing Unit Tests
• Assertions

$this->expectException(RuntimeException::class);
$this->expectExceptionCode(403);
$this->expectExceptionMessage(‘Configuration not found.');
Writing Unit Tests
• Prophecy

- Mock objects

- Expected method calls

- Reveal object when injecting

use PHPUnitFrameworkTestCase;
use ProphecyPhpUnitProphecyTrait;
class RectangleTest extends TestCase
{
use ProphecyTrait;
Writing Unit Tests
• Prophecy

$adderMock = $this->prophesize(Adder::class);
$multiplierMock = $this->prophesize(Multiplier::class);
$adderMock->add($length, $width)
->shouldBeCalled()
->willReturn(10.34001);
$multiplierMock->multiply(2, 10.34001)
->shouldBeCalled()
->willReturn(20.68002);
$rectangle = new Rectangle(
$length,
$width,
$adderMock->reveal(),
$multiplierMock->reveal()
);
Writing Unit Tests
• Prophecy

$dbMock->fetchRow(Argument::any())
->shouldBeCalled()
->willReturn([]);
$asyncBusMock
->dispatch(
Argument::type(DoSomethingCmd::class),
Argument::type('array')
)
->shouldBeCalled()
->willReturn((new Envelope(new stdClass())));
Testing Existing Code
Testing Existing Code
• Problematic Patterns

- Long and complex functions
Testing Existing Code
• Problematic Patterns

- Missing Dependency Injection (DI)

‣ `new Thing();` in functions to be tested
Testing Existing Code
• Problematic Patterns

- exit and die

- print_r

- var_dump

- echo

- other outputs in-line
Testing Existing Code
• Problematic Patterns

- Database interactions

- Resources
Testing Existing Code
• Problematic Patterns

- Out of classes code execution

- Functional code
Testing Existing Code
• Helpful Patterns

- Unit testing promotes good code patterns
Testing Existing Code
• Helpful Patterns

- Dependency Injection

- Classes and functions focused on one thing

- Abstraction

- Interfaces

- Clean code
Testing Existing Code
• Helpful Patterns

- Code that is SOLID

‣ Single-responsibility: should be open for extension,
but closed for modi
fi
cation

‣ Open-closed: should be open for extension, but
closed for modi
fi
cation

‣ Liskov substitution: in PHP, use interface/abstract

‣ Interface segregation: Many client-speci
fi
c interfaces
are better than one general-purpose interface

‣ Dependency inversion: Depend upon abstractions,
[not] concretions
Testing Existing Code
• Helpful Patterns

- KISS
Testing Existing Code
• Test Coverage

- Percent of code covered by tests

- Not aiming for 100%

- No need to test language constructs

- Outputs report in various formats

- Uses Xdebug as driver
Testing Existing Code
class ShapeService
{
public function create(string $shape): int
{
$db = new Db();
return $db->insert('shape', ['shape' => $shape]);
}
public function smsArea(Rectangle $shape, string $toNumber): bool
{
$sms = new Sms([
'api_uri' => 'https://example.com/sms',
'api_key' => 'alkdjfoasifj0392lkdsjf',
]);
$sent = $sms->send($toNumber, 'Area is ' . $shape->area());
(new Logger())
->log('Sms sent to ' . $toNumber . ': Area is ' . $shape->area());
return $sent;
}
}
Testing Existing Code
class ShapeService
{
public function create(string $shape): int
{
$db = new Db();
return $db->insert('shape', ['shape' => $shape]);
}
public function smsArea(Rectangle $shape, string $toNumber): bool
{
$sms = new Sms([
'api_uri' => 'https://example.com/sms',
'api_key' => 'alkdjfoasifj0392lkdsjf',
]);
$sent = $sms->send($toNumber, 'Area is ' . $shape->area());
(new Logger())
->log('Sms sent to ' . $toNumber . ': Area is ' . $shape->area());
return $sent;
}
}
Testing Existing Code
class ShapeServiceCleanedUp
{
public function __construct(
protected Db $db,
protected Sms $sms
) {}
public function create(string $shape): int
{
return $this->db->insert('shape', ['shape' => $shape]);
}
public function smsArea(ShapeInterface $shape, string $toNumber): bool
{
$area = $shape->area();
return $this->sms->send($toNumber, 'Area is ' . $area);
}
Testing Existing Code
use ProphecyTrait;
protected Generator $faker;
public function setUp(): void
{
$this->faker = Factory::create();
}
public function testCreate()
{
$dbMock = $this->prophesize(Db::class);
$smsMock = $this->prophesize(Sms::class);
$shape = $this->faker->word;
$dbMock->insert('shape', ['shape' => $shape])
->shouldBeCalled()
->willReturn(1);
$shapeServiceCleanedUp = new ShapeServiceCleanedUp(
$dbMock->reveal(),
$smsMock->reveal()
);
$shapeServiceCleanedUp->create($shape);
}
Testing Existing Code
public function testSmsArea()
{
$dbMock = $this->prophesize(Db::class);
$smsMock = $this->prophesize(Sms::class);
$shapeMock = $this->prophesize(ShapeInterface::class);
$area = $this->faker->randomFloat();
$shapeMock->area()
->shouldBeCalled()
->willReturn($area);
$toNumber = $this->faker->phoneNumber;
$smsMock->send($toNumber, 'Area is ' . $area)
->shouldBeCalled()
->willReturn(1);
$shapeServiceCleanedUp = new ShapeServiceCleanedUp(
$dbMock->reveal(),
$smsMock->reveal()
);
$shapeServiceCleanedUp->smsArea(
$shapeMock->reveal(),
$toNumber
);
}
Live Examples
Discussion Items
• Convincing Teammates

• Convincing Management
Discussion Items
• Does unit testing slow development down?
Discussion Items
• “I don’t see the bene
fi
t of unit testing”
Discussion Items
• Unit tests for legacy code
Discussion Items
• Other?
Review
• Bene
fi
ts of Unit Testing

• PHPUnit Setup

• Writing Unit Tests

• Testing Existing Code
Unit Testing from Setup to Deployment
• Questions?
Mark Niebergall @mbniebergall
• PHP since 2005

• Masters degree in MIS

• Senior Software Engineer

• Drug screening project

• Utah PHP Co-Organizer

• CSSLP, SSCP Certi
fi
ed and SME

• Endurance sports, outdoors
References
• https://analyze.co.za/wp-content/uploads/
2018/12/441-1170x500.jpg

• http://www.ambysoft.com/artwork/
comparingTechniques.jpg

• https://en.wikipedia.org/wiki/SOLID

More Related Content

PPTX
Unit test
Hieu Le Trung
 
PDF
Stacking Up Middleware
Mark Niebergall
 
PDF
Python Testing Fundamentals
cbcunc
 
PPT
20111018 boost and gtest
Will Shen
 
PDF
Test Driven Development With Python
Siddhi
 
PPT
Stopping the Rot - Putting Legacy C++ Under Test
Seb Rose
 
PDF
Effective testing with pytest
Hector Canto
 
PPTX
TDD and the Legacy Code Black Hole
Noam Kfir
 
Unit test
Hieu Le Trung
 
Stacking Up Middleware
Mark Niebergall
 
Python Testing Fundamentals
cbcunc
 
20111018 boost and gtest
Will Shen
 
Test Driven Development With Python
Siddhi
 
Stopping the Rot - Putting Legacy C++ Under Test
Seb Rose
 
Effective testing with pytest
Hector Canto
 
TDD and the Legacy Code Black Hole
Noam Kfir
 

What's hot (20)

PDF
Modern Python Testing
Alexander Loechel
 
ODT
Testing in-python-and-pytest-framework
Arulalan T
 
KEY
Unit Test Your Database
David Wheeler
 
PPT
Google mock for dummies
Harry Potter
 
ODP
Intro To Spring Python
gturnquist
 
PDF
Testing Legacy Rails Apps
Rabble .
 
PPTX
Laravel Unit Testing
Dr. Syed Hassan Amin
 
PPTX
Vagrant+Rouster at salesforce.com
chorankates
 
ZIP
Test
Eddie Kao
 
PPTX
Unit testing of java script and angularjs application using Karma Jasmine Fra...
Samyak Bhalerao
 
PPTX
Auto Deploy Deep Dive – vBrownBag Style
Robert Nelson
 
PPT
Presentation_C++UnitTest
Raihan Masud
 
ODP
Pyunit
Ikuru Kanuma
 
PDF
Python-nose: A unittest-based testing framework for Python that makes writing...
Timo Stollenwerk
 
ODP
Automated testing in Python and beyond
dn
 
PDF
Fighting Fear-Driven-Development With PHPUnit
James Fuller
 
PDF
Puppet evolutions
Alessandro Franceschi
 
PPTX
Laravel 5.5 dev
RocketRoute
 
PPTX
Unit testing presentation
Arthur Freyman
 
ODP
Unit Testing and Coverage for AngularJS
Knoldus Inc.
 
Modern Python Testing
Alexander Loechel
 
Testing in-python-and-pytest-framework
Arulalan T
 
Unit Test Your Database
David Wheeler
 
Google mock for dummies
Harry Potter
 
Intro To Spring Python
gturnquist
 
Testing Legacy Rails Apps
Rabble .
 
Laravel Unit Testing
Dr. Syed Hassan Amin
 
Vagrant+Rouster at salesforce.com
chorankates
 
Test
Eddie Kao
 
Unit testing of java script and angularjs application using Karma Jasmine Fra...
Samyak Bhalerao
 
Auto Deploy Deep Dive – vBrownBag Style
Robert Nelson
 
Presentation_C++UnitTest
Raihan Masud
 
Pyunit
Ikuru Kanuma
 
Python-nose: A unittest-based testing framework for Python that makes writing...
Timo Stollenwerk
 
Automated testing in Python and beyond
dn
 
Fighting Fear-Driven-Development With PHPUnit
James Fuller
 
Puppet evolutions
Alessandro Franceschi
 
Laravel 5.5 dev
RocketRoute
 
Unit testing presentation
Arthur Freyman
 
Unit Testing and Coverage for AngularJS
Knoldus Inc.
 
Ad

Similar to Unit Testing from Setup to Deployment (20)

PDF
Leveling Up With Unit Testing - php[tek] 2023
Mark Niebergall
 
PDF
Leveling Up With Unit Testing - LonghornPHP 2022
Mark Niebergall
 
PDF
Quality Assurance for PHP projects - ZendCon 2012
Michelangelo van Dam
 
KEY
Workshop quality assurance for php projects tek12
Michelangelo van Dam
 
PPTX
Full Stack Unit Testing
GlobalLogic Ukraine
 
PDF
symfony on action - WebTech 207
patter
 
KEY
Php Unit With Zend Framework Zendcon09
Michelangelo van Dam
 
PDF
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
Enterprise PHP Center
 
PPTX
Test in action week 2
Yi-Huan Chan
 
PDF
Getting started with TDD - Confoo 2014
Eric Hogue
 
PDF
Workshop quality assurance for php projects - phpdublin
Michelangelo van Dam
 
PPT
Test Driven Development with PHPUnit
Mindfire Solutions
 
PDF
Php unit (eng)
Anatoliy Okhotnikov
 
PDF
PHPUnit best practices presentation
Thanh Robi
 
PDF
Testing untestable code - DPC10
Stephan Hochdörfer
 
PDF
Lean Php Presentation
Alan Pinstein
 
PDF
Workshop quality assurance for php projects - ZendCon 2013
Michelangelo van Dam
 
PDF
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
PDF
New Features PHPUnit 3.3 - Sebastian Bergmann
dpc
 
KEY
Unit testing zend framework apps
Michelangelo van Dam
 
Leveling Up With Unit Testing - php[tek] 2023
Mark Niebergall
 
Leveling Up With Unit Testing - LonghornPHP 2022
Mark Niebergall
 
Quality Assurance for PHP projects - ZendCon 2012
Michelangelo van Dam
 
Workshop quality assurance for php projects tek12
Michelangelo van Dam
 
Full Stack Unit Testing
GlobalLogic Ukraine
 
symfony on action - WebTech 207
patter
 
Php Unit With Zend Framework Zendcon09
Michelangelo van Dam
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
Enterprise PHP Center
 
Test in action week 2
Yi-Huan Chan
 
Getting started with TDD - Confoo 2014
Eric Hogue
 
Workshop quality assurance for php projects - phpdublin
Michelangelo van Dam
 
Test Driven Development with PHPUnit
Mindfire Solutions
 
Php unit (eng)
Anatoliy Okhotnikov
 
PHPUnit best practices presentation
Thanh Robi
 
Testing untestable code - DPC10
Stephan Hochdörfer
 
Lean Php Presentation
Alan Pinstein
 
Workshop quality assurance for php projects - ZendCon 2013
Michelangelo van Dam
 
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
New Features PHPUnit 3.3 - Sebastian Bergmann
dpc
 
Unit testing zend framework apps
Michelangelo van Dam
 
Ad

More from Mark Niebergall (20)

PDF
Filesystem Management with Flysystem - php[tek] 2023
Mark Niebergall
 
PDF
Filesystem Management with Flysystem at PHP UK 2023
Mark Niebergall
 
PDF
Developing SOLID Code
Mark Niebergall
 
PDF
BDD API Tests with Gherkin and Behat
Mark Niebergall
 
PDF
BDD API Tests with Gherkin and Behat
Mark Niebergall
 
PDF
Hacking with PHP
Mark Niebergall
 
PDF
Relational Database Design Bootcamp
Mark Niebergall
 
PDF
Starting Out With PHP
Mark Niebergall
 
PDF
Automatic PHP 7 Compatibility Checking Using php7cc (and PHPCompatibility)
Mark Niebergall
 
PDF
Debugging PHP with Xdebug - PHPUK 2018
Mark Niebergall
 
PDF
Advanced PHP Simplified - Sunshine PHP 2018
Mark Niebergall
 
PDF
Defensive Coding Crash Course Tutorial
Mark Niebergall
 
PDF
Inheritance: Vertical or Horizontal
Mark Niebergall
 
PDF
Cybersecurity State of the Union
Mark Niebergall
 
PDF
Cryptography With PHP - ZendCon 2017 Workshop
Mark Niebergall
 
PDF
Defensive Coding Crash Course - ZendCon 2017
Mark Niebergall
 
PDF
Leveraging Composer in Existing Projects
Mark Niebergall
 
PDF
Defensive Coding Crash Course
Mark Niebergall
 
PDF
Impostor Syndrome: Be Proud of Your Achievements!
Mark Niebergall
 
PDF
Cryptography with PHP (Workshop)
Mark Niebergall
 
Filesystem Management with Flysystem - php[tek] 2023
Mark Niebergall
 
Filesystem Management with Flysystem at PHP UK 2023
Mark Niebergall
 
Developing SOLID Code
Mark Niebergall
 
BDD API Tests with Gherkin and Behat
Mark Niebergall
 
BDD API Tests with Gherkin and Behat
Mark Niebergall
 
Hacking with PHP
Mark Niebergall
 
Relational Database Design Bootcamp
Mark Niebergall
 
Starting Out With PHP
Mark Niebergall
 
Automatic PHP 7 Compatibility Checking Using php7cc (and PHPCompatibility)
Mark Niebergall
 
Debugging PHP with Xdebug - PHPUK 2018
Mark Niebergall
 
Advanced PHP Simplified - Sunshine PHP 2018
Mark Niebergall
 
Defensive Coding Crash Course Tutorial
Mark Niebergall
 
Inheritance: Vertical or Horizontal
Mark Niebergall
 
Cybersecurity State of the Union
Mark Niebergall
 
Cryptography With PHP - ZendCon 2017 Workshop
Mark Niebergall
 
Defensive Coding Crash Course - ZendCon 2017
Mark Niebergall
 
Leveraging Composer in Existing Projects
Mark Niebergall
 
Defensive Coding Crash Course
Mark Niebergall
 
Impostor Syndrome: Be Proud of Your Achievements!
Mark Niebergall
 
Cryptography with PHP (Workshop)
Mark Niebergall
 

Recently uploaded (20)

PPTX
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
PDF
Bandai Playdia The Book - David Glotz
BluePanther6
 
PPTX
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
PDF
ShowUs: Pharo Stream Deck (ESUG 2025, Gdansk)
ESUG
 
PPTX
Role Of Python In Programing Language.pptx
jaykoshti048
 
PDF
Balancing Resource Capacity and Workloads with OnePlan – Avoid Overloading Te...
OnePlan Solutions
 
PPTX
Presentation about variables and constant.pptx
safalsingh810
 
PPTX
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
PDF
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
PDF
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
PDF
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
PPTX
PFAS Reporting Requirements 2026 Are You Submission Ready Certivo.pptx
Certivo Inc
 
PPT
Activate_Methodology_Summary presentatio
annapureddyn
 
PDF
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
PDF
Appium Automation Testing Tutorial PDF: Learn Mobile Testing in 7 Days
jamescantor38
 
PDF
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
PPTX
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
PDF
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
PPTX
Odoo Integration Services by Candidroot Solutions
CandidRoot Solutions Private Limited
 
PPTX
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
Bandai Playdia The Book - David Glotz
BluePanther6
 
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
ShowUs: Pharo Stream Deck (ESUG 2025, Gdansk)
ESUG
 
Role Of Python In Programing Language.pptx
jaykoshti048
 
Balancing Resource Capacity and Workloads with OnePlan – Avoid Overloading Te...
OnePlan Solutions
 
Presentation about variables and constant.pptx
safalsingh810
 
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
PFAS Reporting Requirements 2026 Are You Submission Ready Certivo.pptx
Certivo Inc
 
Activate_Methodology_Summary presentatio
annapureddyn
 
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
Appium Automation Testing Tutorial PDF: Learn Mobile Testing in 7 Days
jamescantor38
 
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
Web Testing.pptx528278vshbuqffqhhqiwnwuq
studylike474
 
Download iTop VPN Free 6.1.0.5882 Crack Full Activated Pre Latest 2025
imang66g
 
Odoo Integration Services by Candidroot Solutions
CandidRoot Solutions Private Limited
 
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 

Unit Testing from Setup to Deployment

  • 1. Unit Testing from Setup to Deployment Mark Niebergall
  • 2. Thank You! • Entrata - Venue, Food • JetBrains - 1 free license • Platform.sh - Zoom
  • 4. Objective • Be familiar with how to setup PHPUnit • Familiar with how to test existing code • Know how to write unit tests using PHPUnit with Prophecy • Convince team and management to leverage automated testing
  • 5. Overview • Bene fi ts of Unit Testing • PHPUnit Setup • Writing Unit Tests • Testing Existing Code
  • 7. Bene fi ts of Unit Testing public static function add($a, $b) { return $a + $b; }
  • 8. Bene fi ts of Unit Testing public static function add($a, $b) { return $a + $b; } public function add(float ...$numbers): float { $return = 0; foreach ($numbers as $value) { $return = bcadd( (string) $return, (string) $value, 10 ); } return (float) $return; }
  • 9. Bene fi ts of Unit Testing http://www.ambysoft.com/artwork/comparingTechniques.jpg
  • 10. Bene fi ts of Unit Testing • Automated way to test code - Regression Testing
  • 11. Bene fi ts of Unit Testing • Automated way to test code - Continuous Integration - Continuous Deployment
  • 12. Bene fi ts of Unit Testing • Automated way to test code - Other ways to automatically test code beside functional tests ‣ Behavioral tests (behat) ‣ phpspec (functional) ‣ Selenium (browser automation) ‣ Others?
  • 13. Bene fi ts of Unit Testing • Decrease bugs introduced with code - Decreased time to deployment - Better use of QA team time
  • 14. Bene fi ts of Unit Testing • Decrease bugs introduced with code - High con fi dence in delivered code
  • 15. Bene fi ts of Unit Testing • Con fi dence when refactoring - Tests covering code being refactored - TDD ‣ Change tests ‣ Tests fail ‣ Change code ‣ Tests pass
  • 17. PHPUnit Setup • Install via composer • Setup `phpunit.xml` for con fi guration (if needed) • Run unit tests
  • 18. PHPUnit Setup • phpunit/phpunit • phpspec/prophecy-phpunit • fakerphp/faker
  • 19. PHPUnit Setup composer require --dev phpunit/phpunit composer require --dev phpspec/prophecy-phpunit composer require --dev fakerphp/faker
  • 20. PHPUnit Setup • File phpunit.xml - PHPUnit con fi guration for that project - Documentation: https://phpunit.readthedocs.io/en/9.5/ con fi guration.html 
 <?xml version="1.0" encoding="UTF-8"?> <phpunit colors="true" verbose="true" bootstrap="./tests/Bootstrap.php"> <testsuite name="All Tests"> <directory>./tests</directory> </testsuite> </phpunit>
  • 21. PHPUnit Setup • Running PHPUnit 
 vendor/bin/phpunit tests/ PHPUnit 9.5.6 by Sebastian Bergmann and contributors. Runtime: PHP 8.0.8 Con fi guration: /Users/mniebergall/projects/training/phpunit/ phpunit.xml ......... 9 / 9 (100%) Time: 00:00.032, Memory: 6.00 MB OK (9 tests, 12 assertions)
  • 22. PHPUnit Setup • Running PHPUnit - Within PhpStorm
  • 23. PHPUnit Setup • Directory Structure - PHP fi les in src/ ‣ Ex: src/Math/Adder.php - tests in tests/src/, ‘Test’ at end of fi lename ‣ Ex: tests/src/Math/AdderTest.php
  • 25. Writing Unit Tests public function add(float ...$numbers): float { $return = 0; foreach ($numbers as $value) { $return = bcadd( (string) $return, (string) $value, 10 ); } return (float) $return; }
  • 26. Writing Unit Tests use PHPUnitFrameworkTestCase; class AdderTest extends TestCase { protected Adder $adder; public function setUp(): void { $this->adder = new Adder(); } public function testAdderWithSetup() { $sum = $this->adder->add(3, 7); $this->assertSame(10.0, $sum); }
  • 27. Writing Unit Tests public function testAdderThrowsExceptionWhenNotANumber() { $this->expectException(TypeError::class); $adder = new Adder(); $adder->add(7, 'Can't add this'); }
  • 28. Writing Unit Tests public function testAdderAddsIntegers() { $adder = new Adder(); $sum = $adder->add(7, 3, 5, 5, 6, 4, 1, 9); $this->assertSame(40.0, $sum); } public function testAdderAddsDecimals() { $adder = new Adder(); $sum = $adder->add(1.5, 0.5); $this->assertSame(2.0, $sum); }
  • 29. Writing Unit Tests /** * @dataProvider dataProviderNumbers */ public function testAdderAddsNumbers( float $expectedSum, ...$numbers ) { $adder = new Adder(); $sum = $adder->add(...$numbers); $this->assertSame($expectedSum, $sum); } public function dataProviderNumbers(): array { return [ [2, 1, 1], [2, 1.5, 0.5], ]; }
  • 30. Writing Unit Tests • Test Coverage - Percent of code covered by tests - Not aiming for 100% - No need to test language constructs
  • 31. Writing Unit Tests • Code should be self-contained - No actual database connections - No API calls should occur - No external code should be called ‣ Use testing framework
  • 32. Writing Unit Tests • Assertions $this->assertInstanceOf(Response::class, $response); $this->assertEquals(200, $response->getStatusCode()); $this->assertSame(401, $responseActual->getStatusCode()); $this->assertTrue($dispatched); $this->assertFalse($sent);
  • 33. Writing Unit Tests • Assertions $this->expectException(RuntimeException::class); $this->expectExceptionCode(403); $this->expectExceptionMessage(‘Configuration not found.');
  • 34. Writing Unit Tests • Prophecy - Mock objects - Expected method calls - Reveal object when injecting use PHPUnitFrameworkTestCase; use ProphecyPhpUnitProphecyTrait; class RectangleTest extends TestCase { use ProphecyTrait;
  • 35. Writing Unit Tests • Prophecy $adderMock = $this->prophesize(Adder::class); $multiplierMock = $this->prophesize(Multiplier::class); $adderMock->add($length, $width) ->shouldBeCalled() ->willReturn(10.34001); $multiplierMock->multiply(2, 10.34001) ->shouldBeCalled() ->willReturn(20.68002); $rectangle = new Rectangle( $length, $width, $adderMock->reveal(), $multiplierMock->reveal() );
  • 36. Writing Unit Tests • Prophecy $dbMock->fetchRow(Argument::any()) ->shouldBeCalled() ->willReturn([]); $asyncBusMock ->dispatch( Argument::type(DoSomethingCmd::class), Argument::type('array') ) ->shouldBeCalled() ->willReturn((new Envelope(new stdClass())));
  • 38. Testing Existing Code • Problematic Patterns - Long and complex functions
  • 39. Testing Existing Code • Problematic Patterns - Missing Dependency Injection (DI) ‣ `new Thing();` in functions to be tested
  • 40. Testing Existing Code • Problematic Patterns - exit and die - print_r - var_dump - echo - other outputs in-line
  • 41. Testing Existing Code • Problematic Patterns - Database interactions - Resources
  • 42. Testing Existing Code • Problematic Patterns - Out of classes code execution - Functional code
  • 43. Testing Existing Code • Helpful Patterns - Unit testing promotes good code patterns
  • 44. Testing Existing Code • Helpful Patterns - Dependency Injection - Classes and functions focused on one thing - Abstraction - Interfaces - Clean code
  • 45. Testing Existing Code • Helpful Patterns - Code that is SOLID ‣ Single-responsibility: should be open for extension, but closed for modi fi cation ‣ Open-closed: should be open for extension, but closed for modi fi cation ‣ Liskov substitution: in PHP, use interface/abstract ‣ Interface segregation: Many client-speci fi c interfaces are better than one general-purpose interface ‣ Dependency inversion: Depend upon abstractions, [not] concretions
  • 46. Testing Existing Code • Helpful Patterns - KISS
  • 47. Testing Existing Code • Test Coverage - Percent of code covered by tests - Not aiming for 100% - No need to test language constructs - Outputs report in various formats - Uses Xdebug as driver
  • 48. Testing Existing Code class ShapeService { public function create(string $shape): int { $db = new Db(); return $db->insert('shape', ['shape' => $shape]); } public function smsArea(Rectangle $shape, string $toNumber): bool { $sms = new Sms([ 'api_uri' => 'https://example.com/sms', 'api_key' => 'alkdjfoasifj0392lkdsjf', ]); $sent = $sms->send($toNumber, 'Area is ' . $shape->area()); (new Logger()) ->log('Sms sent to ' . $toNumber . ': Area is ' . $shape->area()); return $sent; } }
  • 49. Testing Existing Code class ShapeService { public function create(string $shape): int { $db = new Db(); return $db->insert('shape', ['shape' => $shape]); } public function smsArea(Rectangle $shape, string $toNumber): bool { $sms = new Sms([ 'api_uri' => 'https://example.com/sms', 'api_key' => 'alkdjfoasifj0392lkdsjf', ]); $sent = $sms->send($toNumber, 'Area is ' . $shape->area()); (new Logger()) ->log('Sms sent to ' . $toNumber . ': Area is ' . $shape->area()); return $sent; } }
  • 50. Testing Existing Code class ShapeServiceCleanedUp { public function __construct( protected Db $db, protected Sms $sms ) {} public function create(string $shape): int { return $this->db->insert('shape', ['shape' => $shape]); } public function smsArea(ShapeInterface $shape, string $toNumber): bool { $area = $shape->area(); return $this->sms->send($toNumber, 'Area is ' . $area); }
  • 51. Testing Existing Code use ProphecyTrait; protected Generator $faker; public function setUp(): void { $this->faker = Factory::create(); } public function testCreate() { $dbMock = $this->prophesize(Db::class); $smsMock = $this->prophesize(Sms::class); $shape = $this->faker->word; $dbMock->insert('shape', ['shape' => $shape]) ->shouldBeCalled() ->willReturn(1); $shapeServiceCleanedUp = new ShapeServiceCleanedUp( $dbMock->reveal(), $smsMock->reveal() ); $shapeServiceCleanedUp->create($shape); }
  • 52. Testing Existing Code public function testSmsArea() { $dbMock = $this->prophesize(Db::class); $smsMock = $this->prophesize(Sms::class); $shapeMock = $this->prophesize(ShapeInterface::class); $area = $this->faker->randomFloat(); $shapeMock->area() ->shouldBeCalled() ->willReturn($area); $toNumber = $this->faker->phoneNumber; $smsMock->send($toNumber, 'Area is ' . $area) ->shouldBeCalled() ->willReturn(1); $shapeServiceCleanedUp = new ShapeServiceCleanedUp( $dbMock->reveal(), $smsMock->reveal() ); $shapeServiceCleanedUp->smsArea( $shapeMock->reveal(), $toNumber ); }
  • 54. Discussion Items • Convincing Teammates • Convincing Management
  • 55. Discussion Items • Does unit testing slow development down?
  • 56. Discussion Items • “I don’t see the bene fi t of unit testing”
  • 57. Discussion Items • Unit tests for legacy code
  • 59. Review • Bene fi ts of Unit Testing • PHPUnit Setup • Writing Unit Tests • Testing Existing Code
  • 60. Unit Testing from Setup to Deployment • Questions?
  • 61. Mark Niebergall @mbniebergall • PHP since 2005 • Masters degree in MIS • Senior Software Engineer • Drug screening project • Utah PHP Co-Organizer • CSSLP, SSCP Certi fi ed and SME • Endurance sports, outdoors