Upgrade to Pro — share decks privately, control downloads, hide ads and more …

BDD with PHPSpec

BDD with PHPSpec

The first time I saw the abbreviation BDD I thought it was a miss-print of TDD (Test Driven Development), but it’s not. It stands for Behaviour Driven Development and it is a technique derived from TDD. The difference between the two is a bit nuanced and best felt when you start using some BDD tools. One such tool is PHPSpec. It will help you write better code and have fun in the process. Sounds good? Let’s give it a try!

konrad_126

October 03, 2019
Tweet

More Decks by konrad_126

Other Decks in Programming

Transcript

  1. It's using examples to talk through how an application behaves...

    And having conversations about those examples. Dan North
  2. a tool which can help you write clean and working

    PHP code using Behaviour Driven Development
  3. a tool which can help you write clean and working

    PHP code using Behaviour Driven Development at the spec level
  4. <?php namespace spec\App; use App\Dog; use PhpSpec\ObjectBehavior; use Prophecy\Argument; class

    DogSpec extends ObjectBehavior { function it_is_initializable() { $this->shouldHaveType(Dog::class); } }
  5. <?php # spec/App class DogSpec extends ObjectBehavior { // ...

    function it_should_make_a_sound() { $this->makeSound()->shouldBe('Vuf Vuf'); } }
  6. // Identity matchers $this->getRating()->shouldBe(5); $this->getTitle()->shouldBeEqualTo("Star Wars"); $this->getReleaseDate()->shouldReturn(233366400); $this->getDescription()->shouldEqual("Inexplicably popular children's

    film"); // Comparison Matcher $this->getRating()->shouldBeLike('5'); // Type Matcher $this->shouldHaveType('Movie'); $this->shouldReturnAnInstanceOf('Movie'); $this->shouldBeAnInstanceOf('Movie'); $this->shouldImplement('Movie'); // Count Matcher $this->getDirectors()->shouldHaveCount(1); // IterableContain Matcher¶ $this->getCast()->shouldContain('Jane Smith'); // Throw Matcher $this->shouldThrow('\InvalidArgumentException')->duringSetRating(-3); $this->shouldThrow('\InvalidArgumentException')->during('setRating', array(-3)); $this->shouldThrow('\InvalidArgumentException')->duringInstantiation(); // ...
  7. <?php # spec/App class DogSpec extends ObjectBehavior { // ...

    function it_can_greet_a_person(Person $person) { $person->name()->willReturn('Mike'); $this->greet($person)->shouldBe('Hello Mike, Vuf Vuf'); } }
  8. <?php # spec/App class DogSpec extends ObjectBehavior { // ...

    function it_can_greet_a_person(Named $named) { $named->name()->willReturn('Mike'); $this->greet($person)->shouldBe('Hello Mike, Vuf Vuf'); } }
  9. <?php # src/App class Dog { public function makeSound() {

    return 'Vuf Vuf'; } public function greet($argument1) { // TODO: write logic here } }
  10. <?php # src/App class Dog { public function makeSound() {

    return 'Vuf Vuf'; } public function greet(Named $named) { return 'Hello ' . $named->name() . 'Vuf Vuf'; } }
  11. <?php # src/App class PersonSpec extends ObjectBehavior { // ..

    function it_returns_the_name_it_was_constructed_with() { $this->beConstructedWith('Mike'); $this->name()->shouldBe('Mike'); } }
  12. <?php # src/App class Person implements Named { public function

    __construct($argument1) { // TODO: write logic here } public function name() { // TODO: Implement name() method. } }
  13. <?php # src/App class Person implements Named { private $name;

    public function __construct(string $name) { $this->name = $name; } public function name() { return $this->name; } }
  14. <?php # spec/App class PersonSpec extends ObjectBehavior { // ...

    function it_returns_new_name_if_renamed() { $this->beConstructedWith('Mike'); $this->renameTo ('Mary'); $this->name()->shouldBe('Mary'); } }
  15. <?php # src/App class Person implements Named { private $name;

    public function __construct(string $name) { $this->name = $name; } public function name() { return $this->name; } public function renameTo($argument1) { // TODO: write logic here } }
  16. <?php # src/App; class Person implements Named { private $name;

    public function __construct(string $name) { $this->name = $name; } public function name() { return $this->name; } public function renameTo(string $name) { $this->name = $name; } }
  17. <?php # spec/App class PersonSpec extends ObjectBehavior { function it_returns_the_name_it_was_constructed_with()

    { $this->beConstructedWith('Mike'); $this->name()->shouldBe('Mike'); } function it_returns_new_name_if_renamed() { $this->beConstructedWith('Mike'); $this->renameTo ('Mary'); $this->name()->shouldBe('Mary'); } }
  18. <?php # spec/App class PersonSpec extends ObjectBehavior { function let()

    { $this->beConstructedWith('Mike'); } function it_returns_the_name_it_was_constructed_with() { $this->name()->shouldBe('Mike'); } function it_returns_new_name_if_renamed() { $this->renameTo ('Mary'); $this->name()->shouldBe('Mary'); } }
  19. <?php # spec/App class DogSpec extends ObjectBehavior { function let(Logger

    $logger) { $this->beConstructedWith($logger); } // ... function it_logs_the_greeting(Named $named, Logger $logger) { $named->name()->willReturn('Mike'); $logger->log('Hello Mike, Vuf Vuf')->shouldBeCalled(); $this->greet($named); } }
  20. <?php # src/App class Dog { public function __construct($argument1) {

    // TODO: write logic here } public function makeSound() { return 'Vuf Vuf'; } public function greet(Named $named) { $greeting = 'Hello ' . $named->name() . ', Vuf Vuf'; return $greeting; } }
  21. <?php # src/App class Dog { private $logger; public function

    __construct(Logger $logger) { $this->logger = $logger; } public function makeSound() { return 'Vuf Vuf'; } public function greet(Named $named) { $greeting = 'Hello ' . $named->name() . ', Vuf Vuf'; $this->logger->log($greeting); return $greeting; } }