SlideShare a Scribd company logo
Leveling Up With
Unit Testing
Mark Niebergall
https://joind.in/talk/906c6
👏 Thank You!
• LonghornPHP Organizers, Sponsors
- Nucleus Security
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, Mockery
✓ 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 (CI)
- Continuous Deployment (CD)
😀 Bene
fi
ts of Unit Testing
• 💻 Automated way to test code
- Other ways to automatically test code
‣ Behavioral (BDD): behat, phpspec
‣ Functional
‣ Acceptance: Selenium
‣ 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
• mockery/mockery
• fakerphp/faker
⚙ PHPUnit Setup
composer require --dev phpunit/phpunit
composer require --dev phpspec/prophecy-phpunit
composer require --dev mockery/mockery
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 Setup
• 💻 Running PHPUnit
vendor/bin/phpunit tests/
PHPUnit 9.5.25 by Sebastian Bergmann and contributors.
Runtime: PHP 8.1.10
Con
fi
guration: /Users/mniebergall/projects/phpunit/phpunit.xml
........... 11 / 11 (100%)
Time: 00:00.025, Memory: 8.00 MB
OK (11 tests, 15 assertions)
⚙ PHPUnit Setup
• 💻 Running PHPUnit
- Within PhpStorm
- https://www.jetbrains.com/help/phpstorm/using-
phpunit-framework.html
⚙ 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
/**
* @dataProvider dataProviderNumbers
*/
public function testAdderAddsNumbers(
float $expectedSum,
...$numbers
) {
$adder = new Adder();
$sum = $adder->add(...$numbers);
$this->assertSame($expectedSum, $sum);
}
public function dataProviderNumbers(): iterable
{
yield 'integer' => [2, 1, 1];
yield 'integers with decimals' => [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
• ⛔ 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
• Mocking
- Built-in Mock Objects
- Prophecy
- Mockery
🧑💻 Writing Unit Tests
• ⚠ Scratching the surface
- Dive deep into each
- See what you like, what works
- Leverage a mix
🧑💻 Writing Unit Tests
• Built-in Mock Objects
- Only mock certain methods, let others run as-is
- Pattern: ->method(…)->with($arg)->willReturn($value)
use PHPUnitFrameworkTestCase;
class RectangleTest extends TestCase
🧑💻 Writing Unit Tests
• Built-in Mock Objects
$adderMock = $this->getMockBuilder(Adder::class)
->onlyMethods(['add'])
->getMock();
$adderMock->method('add')
->with($length, $width)
->willReturn(10.34001);
$multiplierMock = $this->getMockBuilder(Multiplier::class)
->onlyMethods(['multiply'])
->getMock();
$multiplierMock->method('multiply')
->with(2, 10.34001)
->willReturn(20.68002);
$rectangle = new Rectangle(
$length,
$width,
$adderMock,
$multiplierMock
);
🧑💻 Writing Unit Tests
• Prophecy
- Pattern: ->shouldBeCalled()->willReturn($value)
🧑💻 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())));
🧑💻 Writing Unit Tests
• Mockery
- Similar style to built-in
🧑💻 Writing Unit Tests
• Mockery
$adderMock = Mockery::mock(Adder::class);
$multiplierMock = Mockery::mock(Multiplier::class);
$adderMock->shouldReceive('add')
->with($length, $width)
->andReturn(10.34001);
$multiplierMock->shouldReceive('multiply')
->with(2, 10.34001)
->andReturn(20.68002);
$rectangle = new Rectangle(
$length,
$width,
$adderMock,
$multiplierMock
);
⌨ 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
- die
- print_r
- var_dump
- echo
- other outputs in-line
‣ Hint: use expectOutputString
⌨ Testing Existing Code
• ⚠ Problematic Patterns
- Time-sensitive
- sleep
⌨ Testing Existing Code
• ⚠ Problematic Patterns
- Database interactions
- Resources
⌨ Testing Existing Code
• ⚠ Problematic Patterns
- Out of class 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: every class should have only
one responsibility
‣ 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
- DDD
⌨ Testing Existing Code
• ✅ Helpful Patterns
- KISS
- DRY
- YAGNI
⌨ 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 ShapeService
{
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
);
}
💬 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?
• https://joind.in/talk/906c6
Mark Niebergall @mbniebergall
• PHP since 2005
• Masters degree in MIS
• Senior Software Engineer
• Vulnerability Management project (security scans)
• Utah PHP Co-Organizer
• CSSLP, SSCP Certi
fi
ed and Exam Developer
• 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

Similar to Leveling Up With Unit Testing - LonghornPHP 2022

Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
Michelangelo van Dam
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
Mike Lively
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
Michelangelo van Dam
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2Yi-Huan Chan
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yii
madhavi Ghadge
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Continuous Delivery - Automate & Build Better Software with Travis CI
Continuous Delivery - Automate & Build Better Software with Travis CIContinuous Delivery - Automate & Build Better Software with Travis CI
Continuous Delivery - Automate & Build Better Software with Travis CI
wajrcs
 
Unit testing
Unit testingUnit testing
Unit testing
Prabhat Kumar
 
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
Jen Wong
 
Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021
Scott Keck-Warren
 
Automatic testing and quality assurance for WordPress plugins and themes
Automatic testing and quality assurance for WordPress plugins and themesAutomatic testing and quality assurance for WordPress plugins and themes
Automatic testing and quality assurance for WordPress plugins and themes
Otto Kekäläinen
 
2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps
Venkata Ramana
 
Testing untestable Code - PFCongres 2010
Testing untestable Code - PFCongres 2010Testing untestable Code - PFCongres 2010
Testing untestable Code - PFCongres 2010Stephan Hochdörfer
 
Mastering selenium for automated acceptance tests
Mastering selenium for automated acceptance testsMastering selenium for automated acceptance tests
Mastering selenium for automated acceptance testsNick Belhomme
 
Automated Developer Testing: Achievements and Challenges
Automated Developer Testing: Achievements and ChallengesAutomated Developer Testing: Achievements and Challenges
Automated Developer Testing: Achievements and Challenges
Tao Xie
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
Mindfire Solutions
 
How to use selenium successfully
How to use selenium successfullyHow to use selenium successfully
How to use selenium successfully
TEST Huddle
 
Effizientere WordPress-Plugin-Entwicklung mit Softwaretests
Effizientere WordPress-Plugin-Entwicklung mit SoftwaretestsEffizientere WordPress-Plugin-Entwicklung mit Softwaretests
Effizientere WordPress-Plugin-Entwicklung mit Softwaretests
DECK36
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnit
James Fuller
 
Unit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step TrainingUnit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step Training
Ram Awadh Prasad, PMP
 

Similar to Leveling Up With Unit Testing - LonghornPHP 2022 (20)

Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
 
Automated Unit Testing
Automated Unit TestingAutomated Unit Testing
Automated Unit Testing
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yii
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Continuous Delivery - Automate & Build Better Software with Travis CI
Continuous Delivery - Automate & Build Better Software with Travis CIContinuous Delivery - Automate & Build Better Software with Travis CI
Continuous Delivery - Automate & Build Better Software with Travis CI
 
Unit testing
Unit testingUnit testing
Unit testing
 
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
 
Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021Getting Started with Test-Driven Development at Midwest PHP 2021
Getting Started with Test-Driven Development at Midwest PHP 2021
 
Automatic testing and quality assurance for WordPress plugins and themes
Automatic testing and quality assurance for WordPress plugins and themesAutomatic testing and quality assurance for WordPress plugins and themes
Automatic testing and quality assurance for WordPress plugins and themes
 
2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps2010 07-28-testing-zf-apps
2010 07-28-testing-zf-apps
 
Testing untestable Code - PFCongres 2010
Testing untestable Code - PFCongres 2010Testing untestable Code - PFCongres 2010
Testing untestable Code - PFCongres 2010
 
Mastering selenium for automated acceptance tests
Mastering selenium for automated acceptance testsMastering selenium for automated acceptance tests
Mastering selenium for automated acceptance tests
 
Automated Developer Testing: Achievements and Challenges
Automated Developer Testing: Achievements and ChallengesAutomated Developer Testing: Achievements and Challenges
Automated Developer Testing: Achievements and Challenges
 
Test Driven Development with PHPUnit
Test Driven Development with PHPUnitTest Driven Development with PHPUnit
Test Driven Development with PHPUnit
 
How to use selenium successfully
How to use selenium successfullyHow to use selenium successfully
How to use selenium successfully
 
Effizientere WordPress-Plugin-Entwicklung mit Softwaretests
Effizientere WordPress-Plugin-Entwicklung mit SoftwaretestsEffizientere WordPress-Plugin-Entwicklung mit Softwaretests
Effizientere WordPress-Plugin-Entwicklung mit Softwaretests
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnit
 
Unit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step TrainingUnit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step Training
 

More from Mark Niebergall

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

More from Mark Niebergall (20)

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

Recently uploaded

Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
Google
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
Łukasz Chruściel
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
AI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website CreatorAI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website Creator
Google
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Mind IT Systems
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Crescat
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 

Recently uploaded (20)

Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket ManagementUtilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
Utilocate provides Smarter, Better, Faster, Safer Locate Ticket Management
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
 
Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
AI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website CreatorAI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website Creator
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
Introducing Crescat - Event Management Software for Venues, Festivals and Eve...
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 

Leveling Up With Unit Testing - LonghornPHP 2022

  • 1. Leveling Up With Unit Testing Mark Niebergall https://joind.in/talk/906c6
  • 2. 👏 Thank You! • LonghornPHP Organizers, Sponsors - Nucleus Security
  • 3.
  • 5. ✔ 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, Mockery ✓ Convince team and management to leverage automated testing
  • 6. 👀 Overview • 😀 Bene fi ts of Unit Testing • ⚙ PHPUnit Setup • 🧑💻 Writing Unit Tests • ⌨ Testing Existing Code
  • 7. 😀 Bene fi ts of Unit Testing
  • 8. 😀 Bene fi ts of Unit Testing public static function add($a, $b) { return $a + $b; }
  • 9. 😀 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; }
  • 10. 😀 Bene fi ts of Unit Testing http://www.ambysoft.com/artwork/comparingTechniques.jpg
  • 11. 😀 Bene fi ts of Unit Testing • 💻 Automated way to test code - Regression Testing
  • 12. 😀 Bene fi ts of Unit Testing • 💻 Automated way to test code - Continuous Integration (CI) - Continuous Deployment (CD)
  • 13. 😀 Bene fi ts of Unit Testing • 💻 Automated way to test code - Other ways to automatically test code ‣ Behavioral (BDD): behat, phpspec ‣ Functional ‣ Acceptance: Selenium ‣ Others?
  • 14. 😀 Bene fi ts of Unit Testing • 🪲 Decrease bugs introduced with code - Decreased time to deployment - Better use of QA team time
  • 15. 😀 Bene fi ts of Unit Testing • 🪲 Decrease bugs introduced with code - High con fi dence in delivered code
  • 16. 😀 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
  • 18. ⚙ PHPUnit Setup • Install via composer • Setup `phpunit.xml` for con fi guration (if needed) • Run unit tests
  • 19. ⚙ PHPUnit Setup • phpunit/phpunit • phpspec/prophecy-phpunit • mockery/mockery • fakerphp/faker
  • 20. ⚙ PHPUnit Setup composer require --dev phpunit/phpunit composer require --dev phpspec/prophecy-phpunit composer require --dev mockery/mockery composer require --dev fakerphp/faker
  • 21. ⚙ 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>
  • 22. ⚙ PHPUnit Setup • 💻 Running PHPUnit vendor/bin/phpunit tests/
  • 23. ⚙ PHPUnit Setup • 💻 Running PHPUnit vendor/bin/phpunit tests/ PHPUnit 9.5.25 by Sebastian Bergmann and contributors. Runtime: PHP 8.1.10 Con fi guration: /Users/mniebergall/projects/phpunit/phpunit.xml ........... 11 / 11 (100%) Time: 00:00.025, Memory: 8.00 MB OK (11 tests, 15 assertions)
  • 24. ⚙ PHPUnit Setup • 💻 Running PHPUnit - Within PhpStorm - https://www.jetbrains.com/help/phpstorm/using- phpunit-framework.html
  • 25. ⚙ 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
  • 27. 🧑💻 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; }
  • 28. 🧑💻 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); }
  • 29. 🧑💻 Writing Unit Tests public function testAdderThrowsExceptionWhenNotANumber() { $this->expectException(TypeError::class); $adder = new Adder(); $adder->add(7, 'Can't add this'); }
  • 30. 🧑💻 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); }
  • 31. 🧑💻 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], ]; }
  • 32. 🧑💻 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(): iterable { yield 'integer' => [2, 1, 1]; yield 'integers with decimals' => [2, 1.5, 0.5]; }
  • 33. 🧑💻 Writing Unit Tests • 📏 Test Coverage - Percent of code covered by tests - Not aiming for 100% - No need to test language constructs
  • 34. 🧑💻 Writing Unit Tests • ⛔ Self-contained - No actual database connections - No API calls should occur - No external code should be called ‣ Use testing framework
  • 35. 🧑💻 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);
  • 36. 🧑💻 Writing Unit Tests • ✅ Assertions $this->expectException(RuntimeException::class); $this->expectExceptionCode(403); $this->expectExceptionMessage(‘Configuration not found.');
  • 37. 🧑💻 Writing Unit Tests • Mocking - Built-in Mock Objects - Prophecy - Mockery
  • 38. 🧑💻 Writing Unit Tests • ⚠ Scratching the surface - Dive deep into each - See what you like, what works - Leverage a mix
  • 39. 🧑💻 Writing Unit Tests • Built-in Mock Objects - Only mock certain methods, let others run as-is - Pattern: ->method(…)->with($arg)->willReturn($value) use PHPUnitFrameworkTestCase; class RectangleTest extends TestCase
  • 40. 🧑💻 Writing Unit Tests • Built-in Mock Objects $adderMock = $this->getMockBuilder(Adder::class) ->onlyMethods(['add']) ->getMock(); $adderMock->method('add') ->with($length, $width) ->willReturn(10.34001); $multiplierMock = $this->getMockBuilder(Multiplier::class) ->onlyMethods(['multiply']) ->getMock(); $multiplierMock->method('multiply') ->with(2, 10.34001) ->willReturn(20.68002); $rectangle = new Rectangle( $length, $width, $adderMock, $multiplierMock );
  • 41. 🧑💻 Writing Unit Tests • Prophecy - Pattern: ->shouldBeCalled()->willReturn($value)
  • 42. 🧑💻 Writing Unit Tests • Prophecy - Mock objects - Expected method calls - Reveal object when injecting use PHPUnitFrameworkTestCase; use ProphecyPhpUnitProphecyTrait; class RectangleTest extends TestCase { use ProphecyTrait;
  • 43. 🧑💻 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() );
  • 44. 🧑💻 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())));
  • 45. 🧑💻 Writing Unit Tests • Mockery - Similar style to built-in
  • 46. 🧑💻 Writing Unit Tests • Mockery $adderMock = Mockery::mock(Adder::class); $multiplierMock = Mockery::mock(Multiplier::class); $adderMock->shouldReceive('add') ->with($length, $width) ->andReturn(10.34001); $multiplierMock->shouldReceive('multiply') ->with(2, 10.34001) ->andReturn(20.68002); $rectangle = new Rectangle( $length, $width, $adderMock, $multiplierMock );
  • 48. ⌨ Testing Existing Code • ⚠ Problematic Patterns - Long and complex functions
  • 49. ⌨ Testing Existing Code • ⚠ Problematic Patterns - Missing Dependency Injection (DI) ‣ `new Thing();` in functions to be tested
  • 50. ⌨ Testing Existing Code • ⚠ Problematic Patterns - exit - die - print_r - var_dump - echo - other outputs in-line ‣ Hint: use expectOutputString
  • 51. ⌨ Testing Existing Code • ⚠ Problematic Patterns - Time-sensitive - sleep
  • 52. ⌨ Testing Existing Code • ⚠ Problematic Patterns - Database interactions - Resources
  • 53. ⌨ Testing Existing Code • ⚠ Problematic Patterns - Out of class code execution - Functional code
  • 54. ⌨ Testing Existing Code • ✅ Helpful Patterns - Unit testing promotes good code patterns
  • 55. ⌨ Testing Existing Code • ✅ Helpful Patterns - Dependency Injection - Classes and functions focused on one thing - Abstraction - Interfaces - Clean code
  • 56. ⌨ Testing Existing Code • ✅ Helpful Patterns - Code that is SOLID ‣ Single-responsibility: every class should have only one responsibility ‣ 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
  • 57. ⌨ Testing Existing Code • ✅ Helpful Patterns - DDD
  • 58. ⌨ Testing Existing Code • ✅ Helpful Patterns - KISS - DRY - YAGNI
  • 59. ⌨ 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; } }
  • 60. ⌨ 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; } }
  • 61. ⌨ Testing Existing Code class ShapeService { 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); }
  • 62. ⌨ 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); }
  • 63. ⌨ 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 ); }
  • 64. 💬 Discussion Items • Convincing Teammates • Convincing Management
  • 65. 💬 Discussion Items • Does unit testing slow development down?
  • 66. 💬 Discussion Items • “I don’t see the bene fi t of unit testing”
  • 67. 💬 Discussion Items • Unit tests for legacy code
  • 69. 📝 Review • Bene fi ts of Unit Testing • PHPUnit Setup • Writing Unit Tests • Testing Existing Code
  • 70. Unit Testing from Setup to Deployment • 🙋 Questions? • https://joind.in/talk/906c6
  • 71. Mark Niebergall @mbniebergall • PHP since 2005 • Masters degree in MIS • Senior Software Engineer • Vulnerability Management project (security scans) • Utah PHP Co-Organizer • CSSLP, SSCP Certi fi ed and Exam Developer • Endurance sports, outdoors
  • 72. ✏ 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