0
Writing Testable Code
“Testable”?
• When we write object oriented code, we write individual units
(classes / objects and their methods)
• Testab...
Types of Automated Tests
• Unit tests - a test that verifies the behaviour an individual method,
function or class / object...
Why are tests so important?
!4
• When we write code, how do we know it behaves as we expect?
• If we write some code that ...
Benefits of Automated Testing
• Tests prove that our code works as we expect
• Writing our tests makes us think about edge ...
Refactoring
Automated tests allow us to refactor with confidence
Tests + Continuous Integration
• We currently use Jenkins as our continuous integration server
(https://jenkins.dt.awsripp...
Thinking About Dependencies
What is a dependency?
• When we write multiple units of code (multiple classes / objects),
they work together to create a ...
Mandatory Dependencies
• A mandatory dependency is something that the component cannot
function without
• For example, we ...
Mandatory Dependencies
<?php!
! !
class SamsungGalaxy extends Phone!
{!
! private $operatingSystem;!
!
! public function _...
Optional Dependencies
• An optional dependency is something that the component can
function without
• For example, we coul...
Optional Dependencies
<?php!
! !
class SamsungGalaxy extends Phone!
{!
! private $operatingSystem;!
! private $usbConnecti...
Optional Dependencies
<?php!
! !
class SamsungGalaxy extends Phone!
{!
! // ...!
!
! public function receiveCall(PhoneCall...
Why are objects dependent on another?
• In object oriented programming, we use objects (created from
classes) to encapsula...
Example of SRP
• Earlier we talked about injecting an OperatingSystem object into
the SamsungGalaxy phone object
• This is...
Real Code Example
Code Example: User Manager
• Let’s say we have a bunch of users in an application
• We have an object in our application t...
Code Example: User Manager
• Our manager needs to:
• Persist / update users to the database
• Hash passwords for users
• D...
Code Example: User Manager
<?php!
! !
class UserManager extends Phone!
{!
! private $db;!
! private $passwordHasher!
!
! p...
Code Example: User Manager
• With separate components, we can write tests for each of them in
isolation
• We can also swap...
Step 2: Managing Dependencies
Objects With Dependencies
• Separating concerns into different objects means we have to create
multiple objects
• This can...
Example: Inline Instantiation
<?php!
! !
class UserController!
{!
! public function createAction()!
! {!
! ! $passwordHash...
Dependency Injection Containers
(DIC)
DIC: Managing Dependencies
• In our UserController example, we needed to have knowledge
of the dependencies that the UserM...
DIC: Managing Dependencies
• A DIC will manage our objects (sometimes referred to as services)
and their dependencies for ...
Pimple: A simple DIC
<?php!
! !
class Container extends Pimple!
{!
! public function __construct()!
! {!
! ! $this[‘user_m...
Pimple: A simple DIC
<?php!
! !
class Container extends Pimple!
{!
! public function __construct()!
! {!
! ! $this[‘passwo...
Using the DIC
<?php!
! !
class UserController!
{!
! public function createAction()!
! {!
! ! $container = $this->getContai...
What Next?
• Pimple can be implemented on any legacy project, just install it
using composer
• We can start separating con...
Writing Unit Tests
Next Session:
Upcoming SlideShare
Loading in...5
×

Writing Testable Code

156

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
156
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Writing Testable Code"

  1. 1. Writing Testable Code
  2. 2. “Testable”? • When we write object oriented code, we write individual units (classes / objects and their methods) • Testable code is code that we can easily write automated unit tests for • Testable code is of a better quality, more isolated and written to comply with SOLID* principles • This is what we will work towards * more on this later
  3. 3. Types of Automated Tests • Unit tests - a test that verifies the behaviour an individual method, function or class / object • Functional tests - tests that ensure the application does what it is supposed to without caring about how it achieves it • Behavioural testing - verifies that the software behaves as the user would expect it to - usually involves automating the browser
  4. 4. Why are tests so important? !4 • When we write code, how do we know it behaves as we expect? • If we write some code that performs the addition of two numbers, how do we know it handles negative values correctly? • We can manually test our code, but this isn’t good enough • As programmers we should always look to automate our processes to reduce repetition, tests are no exception to this rule.
  5. 5. Benefits of Automated Testing • Tests prove that our code works as we expect • Writing our tests makes us think about edge cases, and what we expect from our code in those cases • Protects against regressions • Let’s us know that something is broken before we ship a release • Reduces the amount of manual testing required
  6. 6. Refactoring Automated tests allow us to refactor with confidence
  7. 7. Tests + Continuous Integration • We currently use Jenkins as our continuous integration server (https://jenkins.dt.awsripple.com) • Jenkins “builds” our project and let’s us know if it’s broken • If we have tests that cover every business rule in our application, we will know the code is broken before we ship a release • Reduces the feedback loop between us and the client • Improves quality
  8. 8. Thinking About Dependencies
  9. 9. What is a dependency? • When we write multiple units of code (multiple classes / objects), they work together to create a working application / website. • We refer to these units as components • A component might rely on another component in order to work • If component X relies on component Y, we say that component X has a dependency on component Y
  10. 10. Mandatory Dependencies • A mandatory dependency is something that the component cannot function without • For example, we could say that a smart phone has a mandatory dependency on an operating system • When a dependency is mandatory, we inject it into the constructor of the dependent object
  11. 11. Mandatory Dependencies <?php! ! ! class SamsungGalaxy extends Phone! {! ! private $operatingSystem;! ! ! public function __construct(OperatingSystem $android)! ! {! ! ! $this->operatingSystem = $android;! ! }! }
  12. 12. Optional Dependencies • An optional dependency is something that the component can function without • For example, we could say that the smart phone optionally depends on a USB connection to a computer • When a dependency is optional, we inject it via a setter method
  13. 13. Optional Dependencies <?php! ! ! class SamsungGalaxy extends Phone! {! ! private $operatingSystem;! ! private $usbConnection;! ! ! public function __construct(OperatingSystem $android)! ! {! ! ! $this->operatingSystem = $android;! ! }! ! ! public function setUsbConnection(UsbConnection $usbConnection)! ! {! ! ! $this->usbConnection = $usbConnection;! ! }! }
  14. 14. Optional Dependencies <?php! ! ! class SamsungGalaxy extends Phone! {! ! // ...! ! ! public function receiveCall(PhoneCall $call)! ! {! ! ! if (null !== $this->usbConnection) {! ! ! ! $this->usbConnection->haltTransfers();! ! ! }! ! ! ! ! $call->answer();! }! }
  15. 15. Why are objects dependent on another? • In object oriented programming, we use objects (created from classes) to encapsulate functionality • Each object should do something specific, and do it well • This is known as Single Responsibility Principle (SRP) - the S in the SOLID principles (we will cover more of these over the next few sessions)
  16. 16. Example of SRP • Earlier we talked about injecting an OperatingSystem object into the SamsungGalaxy phone object • This is a separation of responsibility, because the phone is not implementing the logic of the operating system • If we had all of our logic of the OperatingSystem object inside the SamsungGalaxy object, it would be doing too much and would violate SRP • This would allow us to test our OperatingSystem as a unit of code
  17. 17. Real Code Example
  18. 18. Code Example: User Manager • Let’s say we have a bunch of users in an application • We have an object in our application that is responsible for managing users, the UserManager • The UserManager is where we create, update and delete users in the database • We should create multiple components to ease the UserManager’s job
  19. 19. Code Example: User Manager • Our manager needs to: • Persist / update users to the database • Hash passwords for users • Delete users from the database
  20. 20. Code Example: User Manager <?php! ! ! class UserManager extends Phone! {! ! private $db;! ! private $passwordHasher! ! ! public function __construct(! ! ! ConnectionInterface $db,! ! ! PasswordHasherInterface $passwordHasher! ! ) {! ! ! $this->db = $db;! ! ! $this->passwordHasher = $passwordHasher;! }! }
  21. 21. Code Example: User Manager • With separate components, we can write tests for each of them in isolation • We can also swap our dependencies out easily if we choose to do so, our UserManager won’t care • When writing our tests for the UserManager we can mock* any dependencies (e.g. the DatabaseConnectionInterface) which means we don’t need to test with real dependencies • Mocking allows us to test units of code on their own, rather than doing integration testing (hence the term “Unit Testing”) *more on mocking in a future session
  22. 22. Step 2: Managing Dependencies
  23. 23. Objects With Dependencies • Separating concerns into different objects means we have to create multiple objects • This can get unwieldy when we have several dependencies • This also means that our code has to be aware of all the different dependencies that an object relies on….
  24. 24. Example: Inline Instantiation <?php! ! ! class UserController! {! ! public function createAction()! ! {! ! ! $passwordHasher = new BcryptPasswordHasher();! ! ! $connection = new DatabaseConnection($options);! ! ! ! $userManager = new UserManager($connection, $passwordHasher);! ! }! } This is a nightmare…
  25. 25. Dependency Injection Containers (DIC)
  26. 26. DIC: Managing Dependencies • In our UserController example, we needed to have knowledge of the dependencies that the UserManager required • What if we wanted to change the BcryptPasswordHasher to PbkPasswordHasher? • We would have to change code all over our application (wherever we have used the UserManager)
  27. 27. DIC: Managing Dependencies • A DIC will manage our objects (sometimes referred to as services) and their dependencies for us • If we want to get our UserManager from a DIC, we just need to ask for it - we don’t care what else the UserManager depends on • This allows us to scale the complexity of our object dependencies without complicating our code
  28. 28. Pimple: A simple DIC <?php! ! ! class Container extends Pimple! {! ! public function __construct()! ! {! ! ! $this[‘user_manager’] = function() {! ! ! ! $passwordHasher = new BcryptPasswordHasher();! ! ! ! $connection = new DatabaseConnection();! ! ! ! ! return new UserManager($passwordHasher, $connection);! ! ! };! ! }! }
  29. 29. Pimple: A simple DIC <?php! ! ! class Container extends Pimple! {! ! public function __construct()! ! {! ! ! $this[‘password_hasher’] = function() {! ! ! ! return new BcryptPasswordHasher();! ! ! };! ! ! ! $this[‘db’] = function() {! ! ! ! return new DatabaseConnection();! ! ! };! ! ! ! $this[‘user_manager’] = function($c) {! ! ! ! return new UserManager($c[‘password_hasher’], $c[‘db’]);! ! ! };! }! } Even better…
  30. 30. Using the DIC <?php! ! ! class UserController! {! ! public function createAction()! ! {! ! ! $container = $this->getContainer(); // fetch the container! ! ! $userManager = $container[‘user_manager’];! ! }! } • Our controller action is now much simpler and has no knowledge of the UserManager’s dependencies.
  31. 31. What Next? • Pimple can be implemented on any legacy project, just install it using composer • We can start separating concerns when writing our code, always think about SRP • Read about the SOLID principles and understand them (ask for help if needed)
  32. 32. Writing Unit Tests Next Session:
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×