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

Behat: auto-testez votre application

Behat: auto-testez votre application

Les tests unitaires sont excellents, mais seuls, ils ne vous disent pas si votre application se comporte comme prévu. Un utilisateur peut-il accéder aux enregistrements de quelqu'un d'autre? Vos traductions fonctionnent-elles correctement en fonction des headers des requêtes? Apprenez comment écrire des tests Behat pertinents, comment configurer le tout et comment le backend et le frontend peuvent être développés en parallèle.

Anna Filina

April 05, 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