BDD in Symfony2

BDD Practice Manager at Inviqa
Mar. 4, 2011
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
BDD in Symfony2
1 of 114

More Related Content

More from Konstantin Kudryashov

Modern Agile Project ToolboxModern Agile Project Toolbox
Modern Agile Project ToolboxKonstantin Kudryashov
Being effective with legacy projectsBeing effective with legacy projects
Being effective with legacy projectsKonstantin Kudryashov
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software CostsKonstantin Kudryashov
Modern Project ToolboxModern Project Toolbox
Modern Project ToolboxKonstantin Kudryashov
Bridging The Communication Gap, Fast Bridging The Communication Gap, Fast
Bridging The Communication Gap, Fast Konstantin Kudryashov
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Konstantin Kudryashov

Recently uploaded

Mule Meetup Calgary- API Governance & Conformance.pdfMule Meetup Calgary- API Governance & Conformance.pdf
Mule Meetup Calgary- API Governance & Conformance.pdfNithaJoseph4
"The Intersection of architecture and implementation", Mark Richards"The Intersection of architecture and implementation", Mark Richards
"The Intersection of architecture and implementation", Mark RichardsFwdays
Need for Speed: Removing speed bumps in API ProjectsNeed for Speed: Removing speed bumps in API Projects
Need for Speed: Removing speed bumps in API ProjectsŁukasz Chruściel
EuroBSDCon 2023 - (auto)Installing BSD Systems - Cases using pfSense, TrueNAS...EuroBSDCon 2023 - (auto)Installing BSD Systems - Cases using pfSense, TrueNAS...
EuroBSDCon 2023 - (auto)Installing BSD Systems - Cases using pfSense, TrueNAS...Vinícius Zavam
Common WordPress APIs_ Settings APICommon WordPress APIs_ Settings API
Common WordPress APIs_ Settings APIJonathan Bossenger
The Flutter Job Market At The MomentThe Flutter Job Market At The Moment
The Flutter Job Market At The MomentAhmed Abu Eldahab

Recently uploaded(20)

BDD in Symfony2

Editor's Notes

  1. Hi all, now we’ll be talking about BDD in Symfony2.\n
  2. Who am i? I am insane senior from-birth PHP developer from knpLabs, also known as everzet ;-)\nI’m Symfony user from 2007 and creator of sfLESSPlugin, Capifony deployment script, RestfulControllersBundle, Jade.php and, ofcourse, Behat, about which we’ll be talking today.\n
  3. Little history and timelinening.\nFirst, there was a code. And when codebase become very large, it’s become very hard to test it with hands, so someone started to write code to test code. And this new testing code was called UnitTest.\n
  4. Some time later, someone noticed, that it’s very hard to motivate people about writing tests post-factum. Also, it’s very hard to test systems, that wasn’t built with tests in mind. And system, that hard to test, also means, that it hard to use too. So, someone at some point said: “Hey. Let’s write unit tests first. Before the actual code was even written.”. And this drive unit-testing from testing methodology to design one. So now, we’re not testing, we’re design!\n
  5. But know what? It doesn’t work! No-no. Don’t get me wrong... People understood “test first” part. But they totally missunderstood “design with tests” one. So, in 2003, Dan North described evolutionary methodology called BDD. Or Behavior-Driven Development.\n
  6. So, BDD is a simple evolution of TDD. Not revolution, not replacement - but evolution.\n
  7. Evolution is all about elliminating dinosaurs inside everyone of us.\n
  8. TDD indeed has mistake. And what’s even worse, it in it’s name!\n
  9. This “TEST” word. Think for a minute. Are we talking bout tests??? Really! It confuse people. They try to test code, that doesn’t exists and in some cases - they can’t! Because before test something, we need to DESIGN something.\n
  10. So, in reality, we’re talking not about tests, but about software design! And know what? SoftwareDesign-Driven Development is even more stupid therm, than TDD, so\n
  11. In 2003 Dan North proposed to call it Behavior-Driven Development. Cuz really, Behavior of software is most important thing in software itself. Soft without or with wrong Behavior doesn’t makes sense!\n
  12. So, Dan started with simple conventions for evolutionize TDD into BDD in mind of developers. Cuz we must start there first.\n
  13. First rule is test method names should be sentences. Cuz this how we’re thinking about things. We want to test, that “thing must do something”, and not “testThing!”.\n
  14. Another big change is replacement of words “test” everywhere. That was big mistake with TDD. Developers has taken existsing UnitTesting tools, built for TESTING and started to use them for DESIGN. That’s totally wrong! You can’t totally concentrate on design, when you’re writing word “test” everywhere - in test names in test class. I even used this word twice to describe this! So, replace it with something more behavioral, like “should”. Class should do something!\n
  15. So, testcase class should be nouns, which should do something. This means, that your test methods must create full sentenses with testcase class names. In this example - “CustomerTable should find customer by ID”.\n
  16. But that’s not all. Assertions, that we love and use everyday is also test-centic. They focuses on testing, rather than design. We should describe behaviors, not testing something unexistent.\n
  17. So, in better world it should be something like this.\n
  18. And Dan North was not the only one, who believed in this whole new design methodology. Some developers taken all that rules and started to create new tools.\n
  19. So, first BDD frameworks type. Specification-oriented BDD Frameworks. Or just AsteriskSpec.\n
  20. First full-featured Spec framework was Ruby’s RSpec, created by Dave Astels and team. He implemented all Dan North proposals, including assertions to should’s change (thanks to Ruby OOP model).\n
  21. Second is cool JSpec for JS Spec testing by TJ. By the way, this is the guy, who created Express, Jade and Stylo frameworks for node.js ;-)\n
  22. And the last one, is ofcourse PHP Spec framework by Alex Rudakov, called Fabulous. Yes, we have PHPSpec, but it died right after it was born. And it was by reason. And reason is PHP itself. It hasn’t got reach OOP model like Ruby - we can’t extend core objects with our native methods, we must use “dashgreater” or “arrow” instead of dots and we haven’t got reach DSL abilities, that Ruby has. So, i don’t really believe in Spec frameworks for PHP. I simply use first three BDD rules in PHPUnit. But if you want to try what is full-stack Spec framework in PHP - use Fabulous. It’s PHPUnit extension and it’s quite good.\n
  23. Example time. This is RSpec test from rspec site. As you can see, it’ very descriptive and doesn’t looks like UnitTest at all. At first glance... We decribing Bowling score. Describing, that it returns 0 for all gutter game. And in this state, bowling score should be equals to zero. Quite cool!\n
  24. Ok. Let’s summarize. When you writing UnitTests (in RSpec, JSpec or still in PHPUnit) - write class specification instead of TEST! You’re designing, not testing! Remember it!\n
  25. But Spec BDD is not all. Now, we’ll be talking about something really interesting. And it’s called Scenario oriented BDD.\nAt the end of 2004, Dan noticed huge amount of analysis parts in previously declared BDD methodology. And after some brainstorming, he decided to apply all of this behavior-driven thinking to defining requirements.\n
  26. The aim of this work was to built consistent vocabulary for\n
  27. testers\n
  28. analysts\n
  29. developers\n
  30. and business people\n
  31. One vocabulary to rule them all! And if it works, then\n
  32. We would be well on the way to eliminating some of the ambiguity and miscommunication that occur when technical people talk to business people. One vocabulary to set communication between business and technical people. So, in contrast with Spec BDD, which focuses on internal product design, Scenario BDD is almost all about\n
  33. communications! And all we know, that this is hardest part in software development. Ofcourse, when we have business people on project. When we not - we’re almost happy. But let’s be realist, businessman lives inside every one of us, and we need to be able to talk with him too.\n
  34. So, Dan started with simple story template.\n
  35. Where:\nx - the benefit OR value of the feature\ny - the person (role) who will benefit that value from this feature\nz - some feature\n
  36. Its strength is that it forces you to identify the value of a story when you first define it. When there is no real business value for a story, it often comes down to something like ” . . . I want [some feature] so that [I just do, ok?].”\n
  37. A Story’s or Feature’s behavior is simply its acceptance criteria.\n– if the system fulfills all the acceptance criteria, it’s behaving correctly; if it doesn't, it isn't.\nSo, we need a template to simply capture a story’s acceptance criteria.\n
  38. So, Dan started to describe it in terms of scenarios, which took the following form\n
  39. So, Dan started to describe it in terms of scenarios, which took the following form\n
  40. And one feature can have multiple acceptance criterias OR\n
  41. scenarios.\nThat’s the all idea of Scenario BDD. Simple enough, i think!\n
  42. But don’t mess it with Spec BDD. I personally think, that Spec and Scenario BDD is very different approaches. And if Spec BDD is simple evolution of UnitTesting TDD, then Scenario BDD is evolution of acceptance tests (or functional tests if you like). It’s 2 different stages of BDD. And if you’re building good system - you need them both. Both unit and functional tests, both class specifications and feature descriptions.\n
  43. Again. Ruby guys. Particulary same guys, who bring RSpec to us, created full-featured DSL (Domain Strict Language), based on Scenario BDD proposals by Dan North. This DSL gets called Gherkin\n
  44. And it’s very similar to good old Dan’s template. This is Dan North’s template\n
  45. This is Gherkin. They simply declared parser and lexer for keywords and added optional titles for features and scenarios. And cool part in DSL’s is that we can do anything with it. It’s our own custom language. And Gherkin, for example, support internationalization. It has translation to\n
  46. french\n
  47. japanize\n
  48. russian\n
  49. and even english pirate’ish\n
  50. As i said already, titles and even feature description is optional. You can omit it if you want, but don’t!\n
  51. And yeah. Most important one. We’re talking about acceptance criterias. And they, ofcourse should be executable. Gherkin itself was created as part of Cucumber project. Wich is acceptance testing framework, built around Custom BDD DSL, called later Gherkin.\n
  52. And now PHP has all this coolness to with Behat acceptance tester and Behat\\Gherkin parser.\nIt’s written in PHP5.3 and uses bunch of great Symfony2 components, such as Console, DependencyInjection and EventDispatcher. Which means, that Behat is not a port, but all-sufficient php project, that’s easy to use and extend (thanks to DependencyInjection).\n
  53. Ok. How it works. Let’s take a look at simple Gherkin feature. We have feature with title and description and titled scenarios in it with givens (or simply steps). Gherkin parses this into abstract syntax tree and builds\n
  54. something like this. FeatureNode is object with title and description, that has 2 ScenarioNodes with titles, every which has 3 StepNodes.\nAfter parsing, Gherkin passes this structures to Behat itself, which visits every node and runs tests agains it. Steps itself are fine-grained enough to be represented directly in code.\n
  55. Let’s try this “Given I have a bank account example”.\n“Given” is a keyword and “I have a bank account” is simple text. We need some technique to match this and later more complicated texts.\n
  56. We will use regular expressions for that. Here you see simple regular expression, that will match only “I have a bank account” string. But we can define regexp, that will match strings started with or ended with something.\nOk. We matched some step to this definition. What’s next? We need to do something!\n
  57. So, second argument to this definition setup call would be simple callback function. Also, we need to hold this definitions inside something, to find them fast.\n
  58. This something is called DefinitionDispatcher. And it’s available as $steps variable inside every definitions file.\n
  59. But wait... What’s that strange exception get thrown in our callback? Case is, doing something inside our own callback is not enough to call this a test. We need some technique to specify step execution state. Behat has 6 different step types.\n
  60. First one is pending steps. Steps, that throws Pending() exception - gets marked as pending OR TBD steps.\n
  61. Undefined step is a steps, for which Behat can’t find proper definition. Or in dev terms - RegEx doesn’t match any definition.\n
  62. When single step matches multiple definitions - Behat mark it as Ambiguous, cuz it can’t decide which definition to call. So, be accurate when writing definition regexps.\n
  63. Failed step is any step, that throws any other than Pending exception. It means, that if your callback code calls something, that throw exception - step will fail. If your callback throws exception itself - it will fail too.\n
  64. Every step, that follow pending/undefined or failed gets marked as skipped and never gets executed.\n
  65. All other steps - is passed. So, step that doesn’t throw exception - passes.\n
  66. So, our “I have a bank account” step will get pending status.\nLet’s add another step definition.\n
  67. We have a bank account and we want to deposit some money to it.\n
  68. \n
  69. Notice, in that case our RegExp has number matcher, which will become first argument of our callback. Every parens matcher in your regexp - will become callback argument. Argument name doesn’t matter.\nIn our case, dollars variable will be populated with value 35\nBut wait. What to do with this dollars? We need to maintain some states between our scenario context.\n
  70. We have scenario environment for that. It’s simple PHP object, extended from \\stdClass, which means, that it works as variable and closure holder. It gets passed into every callback as first argument. It means, that EVERY callback always has at least one first arguments and it’s Environment variable. New environment gets created before every scenario run, so every scenario has it’s own context.\n
  71. Let’s add a code.\nWe create BankAccount and save it in environment object.\nThen we call “deposit” method, saved on BankAccount object.\nThat simple. But now, we need to test outcome.\n
  72. That’s for what “Then” steps were invented. Let’s write definition for that step.\n
  73. We need to test, that our balance is 35$. And if not - step must fail. We can do this simply by manually comparing 2 variables (matched one and saved in environment one) and throw exception if they not match.\n
  74. OR. We can use PHPUnit assertions, that in case of fail will print beautiful exception output. All you need is 2 require_once statements in behat bootstrap script.\n
  75. All steps together in one file. Looks cool, isn’t it?\n
  76. And you can event use chaining for better readability.\n
  77. But we’re here because of Symfony2 Bundle, which glues Symfony2 and Behat\n
  78. To install it, visit bundle page on symfony2bundles site\n
  79. Setup project structure\nAll your features will be hosted under Bundle/Tests/Features. Notice, that this time, features starts from uppercase.\n
  80. Run all Bundle features\n
  81. BehatBundle doesn’t make sense without bundled step definitions.\nYes, Bundle comes with predefined steps, so in most cases, you will simply write feature without even opening step definitions.\n
  82. We have Browser Steps. Like “Given I am on the ...”, “When I go to ...” etc.\n
  83. Form steps. You can fill fields, select variants, check checkboxes and even attach the file in fileinput. Then, simply press form button.\n
  84. Request testing. Test request method, request cookes\n
  85. Or even response statuses. Test response status code, response content or even header. If something wrong happened - simply print response body with “Then Print output”\n
  86. Let’s take a loot at example. We want to implement “User logins” feature\n
  87. We always start from business value, role and feature description, remember?\n
  88. Then, it’s time to define our first scenario title. It must be well-descriptive. “Existing user can login”\n
  89. Also, let’s describe scenario, where non-existing user can’t login\n
  90. And add steps.\nWe have users in DB, we are on login page, filling in form fields and pressing button, checking later that response contains needed message.\n
  91. Oh, wait. This 2 steps will populate database with fixtures. And every scenario in this feature will have them. So, let’s DRY things little bit.\n
  92. Let’s move\n
  93. this step to background section. Steps, added to background section will be executed before every scenarios and will share this scenario environment (or context). But wait! What if later we will want to add some additional users into DB? Then we will add this step again and again, simply replacing username and password. Let’s DRY this too.\n
  94. Steps can accept multiline arguments. One of this is table. This table will be passed to definition, from where we will can iterate through data in it... later.\n
  95. And again. Both scenario steps batch looks the same. And when we’ll have more than 3 such scenarios - it will be hurt. So, let’s refactor it to\n
  96. To scenario outline. We replace all data values with TOKENS. This tokens later will be populated with\n
  97. examples, that is simple\n
  98. Gherkin table. Every row, except header one will be executed as simple scenario.\n
  99. Now it’s the time to run our first bundle feature. It has one undefined step (fixture load).\n
  100. Let’s define it. BehatBundle extends default Behat environment little bit. So we’re able to get application kernel, container or event Doctrine entity manager. Second argument to callback is TableNode. You can get rows hash with “getRowHash” method. Persist our new users and flash them. That’s simple\n
  101. There’s one more thing left. The 2 most requested freatures in Behat are.\n
  102. \n
  103. And by in-browser testing lot of people really means Selenium, but personally i prefer Sahi one. It’s simplier to configure and use.\n
  104. We can use Goutte to test other applications. Goutte could make requests to any application and return response.\n
  105. And, we should be able to inventionally support Selenium ofcourse\n
  106. And sfBrowser for sf1 functional testing\n
  107. And Symfony2 client, ofcourse. The hardest part in whole this zoo of tools is API. Every tool has it’s own, very different API. So we need some level of abstraction above them, to be able to talk with them\n
  108. through one clean API\n
  109. And this tool is called Mink. It’s an browser emulation abstraction layer. It defines whole bunch of default actions available on your browser. And it could support almost any tool on the market through Drivers model. Let’s see an example.\n
  110. Oh, yeah. Did i mentioned, that Mink is part of Behat, but standalone library itself, so you can use it without Behat in you phpUnit tests, like this one. We have 2 tests. One is using Symfony2 Client component, another one is using Sahi in-browser testing. The most interesting parts here is\n
  111. Driver and session initialization. All work is done inside Mink session. But first, you must create a driver. Then, you create new Mink session and give it your new driver instance. All next steps is the same in two methods. Same API to rule 2 insanely different tools. Cool? But what about Behat?\n
  112. Let’s rewrite our old feature.\nDone! Ok. And what if, at some point i’ve decided to actually run this test inside browser (by default, mink will use Symfony2Client). Let’s rewrite it again...\n
  113. Done!\n
  114. \n