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

Behat: Why and How?

Behat: Why and How?

Unit tests are great, but on their own, they don't tell you whether your application behaves as expected. Can a user access someone else's records? Do your translations work correctly based on request headers? Learn how to write relevant Behat tests, how to set everything up and how a backend and a frontend can be developed in parallel.

Avatar for Anna Filina

Anna Filina

March 07, 2018
Tweet

More Decks by Anna Filina

Other Decks in Programming

Transcript

  1. class CartTest extends TestCase { public function testGetTax() { $mock

    = $this->getMock('Cart',['getTaxRate']); $mock->expects($this->once()) ->method('getTaxRate') ->will($this->returnValue(0.15)); $this->assertEquals(15, $mock->getTax(100)); } }
  2. Feature: Cart Items In order to let customers purchase products

    As a developer I need to add items to the shopping cart Background: Given the fixtures file "cart_items.yml" is loaded Scenario: List own cart items Given I send a "GET" request to "/api/users/1/cart" Then the response status code should be 200 And the JSON node "data" should have 2 elements
  3. $ vendor/bin/behat Feature: Cart Items In order to let customers

    purchase products As a developer I need to add items to the shopping cart Background: Given the fixtures file "cart_items.yml" is loaded
 Scenario: List own cart items Given I send a "GET" request to "/api/users/1/cart" Then the response status code should be 200 And the JSON node "data" should have 2 elements 1 scenario (1 passed) 4 steps (4 passed) 0m0.31s (29.05Mb)
  4. Feature: Cart Items In order to let customers purchase products

    As a developer I need to add items to the shopping cart Background: Given the fixtures file "cart_items.yml" is loaded Scenario: List own cart items Given I send a "GET" request to "/api/users/1/cart" Then the response status code should be 200 And the JSON should be equal to file "users_1_cart.json"
  5. /api/users/1/cart { "data": [ { "id": 2, "name": "Product 2",

    "price": 10, "quantity": 2 }, { "id": 1, "name": "Product 1", "price": 10, "quantity": 2 } ] } Backend dev Frontend dev
  6. --- Expected +++ Actual @@ @@ "data": [ { "id":

    2, - "name": "Product 2", + "name": "WRONG DATA", "price": 10, "quantity": 2 },
  7. Scenario: Unauthenticated list Given I send a "GET" request to

    "/api/users/1/cart" Then the response status code should be 401 Scenario: List own cart items Given I add "Authorization" header equal to "Bearer TOKEN_1" And I send a "GET" request to "/api/users/1/cart" Then the response status code should be 200
  8. Scenario: List another user's cart items Given I add "Authorization"

    header equal to "Bearer TOKEN_1" And I send a "GET" request to "/api/users/2/cart" Then the response status code should be 403
  9. Background: Given the fixtures file "expired_token.yml" is loaded Scenario: Expired

    token Given I add "Authorization" header equal to "Bearer TOKEN_1" And I send a "GET" request to "/api/users/1/cart" Then the response status code should be 401
  10. Scenario: List cart items in French Given I add "Accept-Language"

    header equal to "fr-CA,en;q=0.9"
 And I send a "GET" request to "/api/users/1/cart" Then the response status code should be 200 And the JSON should be equal to file "users_1_cart_fr.json"
  11. Scenario: List own cart items Given I add "Authorization" header

    equal to "Bearer TOKEN_1" And I send a "GET" request to "/api/users/1/cart" Then the response status code should be 200 And max 3 queries were executes And query time is under 0.05 seconds
  12. I need my API to go faster. How much faster?

    It takes 3s.
 Bring it under 0.5 Got it.
  13. Given I add "Authorization" header equal to "Bearer TOKEN_1"
 Given

    I send a "GET" request to "/api/users/1/cart"
 Then the response status code should be 200
  14. Given the fixtures file "expired_token.yml" is loaded 
 Then max

    3 queries were executes
 Then query time is under 0.05 seconds
  15. class JsonContext extends \Behatch\Context\JsonContext { /** * @Then the JSON

    should be equal to file :filename */ public function theJsonShouldBeEqualToFile(string $filename):void { $actualJson = json_encode( $this->getJson()->getContent(), JSON_PRETTY_PRINT ); $expectedJson = file_get_contents( __DIR__ . '/../../json/'.$filename ); PHPUnit\Framework\Assert::assertJsonStringEqualsJsonString( $expectedJson, $actualJson ); } }
  16. /** * @Given the fixtures file :filename is loaded */

    public function loadYamlFixtures(string $filename):void { $loader = new \Nelmio\Alice\Loader\NativeLoader(); $objectSet = $loader->loadFile(__DIR__.'/../../fixtures/'.$filename); foreach ($objectSet->getObjects() as $object) { $className = get_class($object); $this->em->persist($object); } $this->em->flush(); }
  17. Feature: Product search Background: Given the fixtures file "products.yml" is

    loaded Scenario: Search existing products Given I am on "/products/Elder+Scrolls" Then the response status code should be 200 And I should see 5 "div.product" elements
  18. Feature: Product search Background: Given the fixtures file "products.yml" is

    loaded Scenario: Search existing products Given I am on "/products/Elder+Scrolls" Then the response status code should be 200 And I should see 5 "div.product" elements 1 scenario (1 passed) 4 steps (4 passed) 0m0.28s (29.15Mb)
  19. @javascript Scenario: Filter products Given I am on "/products" When

    I fill in "search" with "path" Then I should see 1 "div.product.visible" element No :visible pseudoclass
  20. Feature: Product search Background: Given the fixtures file "products.yml" is

    loaded @javascript Scenario: Filter products Given I am on "/products" When I fill in "search" with "path" Then I should see 1 "div.product.visible" element 1 scenario (1 passed) 4 steps (4 passed) 0m2.27s (20.53Mb)
  21. • Limit number of browser tests. • Test the JS

    using JS tooling. • Focus on critical path (checkout). Tips
  22. • Does the app do what the user wants? •

    Useful for "design by contract". • Security, performance, etc. • API, HTML & browser. Takeaways