Writing Testable Code
“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
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
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.
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
Refactoring
Automated tests allow us to refactor with confidence
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
Thinking About Dependencies
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
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
Mandatory Dependencies
<?php!
! !
class SamsungGalaxy extends Phone!
{!
! private $operatingSystem;!
!
! public function __construct(OperatingSystem $android)!
! {!
! ! $this->operatingSystem = $android;!
! }!
}
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
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;!
! }!
}
Optional Dependencies
<?php!
! !
class SamsungGalaxy extends Phone!
{!
! // ...!
!
! public function receiveCall(PhoneCall $call)!
! {!
! ! if (null !== $this->usbConnection) {!
! ! ! $this->usbConnection->haltTransfers();!
! ! }!
! !
! ! $call->answer();!
}!
}
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)
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
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 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
Code Example: User Manager
• Our manager needs to:
• Persist / update users to the database
• Hash passwords for users
• Delete users from the database
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;!
}!
}
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
Step 2: Managing Dependencies
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….
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…
Dependency Injection Containers
(DIC)
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)
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
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);!
! ! };!
! }!
}
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…
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.
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)
Writing Unit Tests
Next Session:

Writing Testable Code

  • 1.
  • 2.
    “Testable”? • When wewrite 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.
    Types of AutomatedTests • 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.
    Why are testsso 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.
    Benefits of AutomatedTesting • 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.
    Refactoring Automated tests allowus to refactor with confidence
  • 7.
    Tests + ContinuousIntegration • 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.
  • 9.
    What is adependency? • 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.
    Mandatory Dependencies • Amandatory 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.
    Mandatory Dependencies <?php! ! ! classSamsungGalaxy extends Phone! {! ! private $operatingSystem;! ! ! public function __construct(OperatingSystem $android)! ! {! ! ! $this->operatingSystem = $android;! ! }! }
  • 12.
    Optional Dependencies • Anoptional 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.
    Optional Dependencies <?php! ! ! classSamsungGalaxy extends Phone! {! ! private $operatingSystem;! ! private $usbConnection;! ! ! public function __construct(OperatingSystem $android)! ! {! ! ! $this->operatingSystem = $android;! ! }! ! ! public function setUsbConnection(UsbConnection $usbConnection)! ! {! ! ! $this->usbConnection = $usbConnection;! ! }! }
  • 14.
    Optional Dependencies <?php! ! ! classSamsungGalaxy extends Phone! {! ! // ...! ! ! public function receiveCall(PhoneCall $call)! ! {! ! ! if (null !== $this->usbConnection) {! ! ! ! $this->usbConnection->haltTransfers();! ! ! }! ! ! ! ! $call->answer();! }! }
  • 15.
    Why are objectsdependent 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.
    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.
  • 18.
    Code Example: UserManager • 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.
    Code Example: UserManager • Our manager needs to: • Persist / update users to the database • Hash passwords for users • Delete users from the database
  • 20.
    Code Example: UserManager <?php! ! ! class UserManager extends Phone! {! ! private $db;! ! private $passwordHasher! ! ! public function __construct(! ! ! ConnectionInterface $db,! ! ! PasswordHasherInterface $passwordHasher! ! ) {! ! ! $this->db = $db;! ! ! $this->passwordHasher = $passwordHasher;! }! }
  • 21.
    Code Example: UserManager • 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.
    Step 2: ManagingDependencies
  • 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.
    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.
  • 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.
    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.
    Pimple: A simpleDIC <?php! ! ! class Container extends Pimple! {! ! public function __construct()! ! {! ! ! $this[‘user_manager’] = function() {! ! ! ! $passwordHasher = new BcryptPasswordHasher();! ! ! ! $connection = new DatabaseConnection();! ! ! ! ! return new UserManager($passwordHasher, $connection);! ! ! };! ! }! }
  • 29.
    Pimple: A simpleDIC <?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.
    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.
    What Next? • Pimplecan 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.