SlideShare ist ein Scribd-Unternehmen logo
1 von 72
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Ähnlich wie Leveling Up With Unit Testing - LonghornPHP 2022

Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
Yi-Huan Chan
 
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
Michelangelo van Dam
 
Testing untestable Code - PFCongres 2010
Testing untestable Code - PFCongres 2010Testing untestable Code - PFCongres 2010
Testing untestable Code - PFCongres 2010
Stephan Hochdörfer
 
Mastering selenium for automated acceptance tests
Mastering selenium for automated acceptance testsMastering selenium for automated acceptance tests
Mastering selenium for automated acceptance tests
Nick Belhomme
 

Ähnlich wie 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
 

Mehr von Mark Niebergall

Mehr von 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!
 

Kürzlich hochgeladen

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Kürzlich hochgeladen (20)

Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...How to Choose the Right Laravel Development Partner in New York City_compress...
How to Choose the Right Laravel Development Partner in New York City_compress...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 

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