64
Jean-Michel Garnier | 21croissants.com XP Day France | 6 mai 2008 Introduction à RSpec Framework de BDD & Tests d'Acceptation

Intro a RSpec, BDD, webapps User Acceptance Testing

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Intro a RSpec, BDD, webapps User Acceptance Testing

Jean-Michel Garnier | 21croissants.com

XP Day France | 6 mai 2008

Introductionà RSpecFramework de BDD & Tests d'Acceptation

Page 2: Intro a RSpec, BDD, webapps User Acceptance Testing

2

Bonjour! Hi! Hola!

Mon blog: 21croissants.com linqia Mind map: http://www.21croissants.com/bdd

Page 3: Intro a RSpec, BDD, webapps User Acceptance Testing

3

Mind map de la présentation

Page 4: Intro a RSpec, BDD, webapps User Acceptance Testing

Origine du BDD

Page 5: Intro a RSpec, BDD, webapps User Acceptance Testing

Origine du BDD

Page 6: Intro a RSpec, BDD, webapps User Acceptance Testing

1975: The Mythical Man-Month

● ¼ Spécificier● 1/6 Coder● Relire le code!

● ½ Tests !!!

Page 7: Intro a RSpec, BDD, webapps User Acceptance Testing

1994: 1er framework Tests Unitaires

Kent Beck, article “Simple Smalltalk Testing”

Class: SetTestCase superclass: TestCase instance variables: empty full

SetTestCase>>setUp empty := Set new.

SetTestCase>>testAdd empty add: 5. self should: [empty includes: 5]

Page 8: Intro a RSpec, BDD, webapps User Acceptance Testing

1998: Junit

class TestMath extends TestCase { public void testAdd() { int num1 = 2; int num2 = 2; int expected = 4; int result = Math.add(num1, num2); assertEquals(expected, result); }}

Page 9: Intro a RSpec, BDD, webapps User Acceptance Testing

Ecrire les tests

avant

le code

2002: TDD

Page 10: Intro a RSpec, BDD, webapps User Acceptance Testing

2003: TestDox (Junit) public class FooTest extends TestCase { public void testIsASingleton() {} public void testAReallyLongNameIsAGoodThing() {}}

Foo- is a singleton- a really long name is a good thing

génère la doc de la classe

Page 11: Intro a RSpec, BDD, webapps User Acceptance Testing

2005: BDD=TDD+should+behaviour

class OldSchoolAgileDeveloperTest < TestCase def setup @ an_agile_developer = OldSchoolAgileDeveloper.new end

def test_should_write_tests_before_code assert_true @an_agile_developer.is_writing_code_before_tests? end

Page 12: Intro a RSpec, BDD, webapps User Acceptance Testing

describe AgileDeveloperBDD, "behaves like a coooool dude" do before :each do @an_agile_developer= AgileDeveloperBDD.new end it {

@an_agile_developer.should be_writing_code_before_specs }

BDD is cool

Page 13: Intro a RSpec, BDD, webapps User Acceptance Testing

TDD is old school

BDD is cool!

Page 14: Intro a RSpec, BDD, webapps User Acceptance Testing

2008: La Controverse de Valladolid

Le BDD a-t-il une âme?

“L'apparition du terme BDD m'a énervé dès l'origine. Il n'y a rien de nouveau par rapport au TDD, on a juste l'impression que des gens on voulu se rendre intéressant en critiquant le TDD (mal fait) et en utilisant un nouveau terme pour ce qui n'est autre que le TDD (bien fait).”

D.W.(19/02/2008 8:09)

Page 15: Intro a RSpec, BDD, webapps User Acceptance Testing

Le BDD en une phrase

"I would say that TDD is a tool to help you solve the problem of designing and implementing behavior. xUnit works fine in that regard, but RSpec reduces the semantic distance between the developer and the problem domain."

Pat Maddox (26/07/2007 00:47)

Page 16: Intro a RSpec, BDD, webapps User Acceptance Testing

2006 - Présent:

javascript

● easyj● Instinct● jtestr

● RSpec● expectation● bacon● shoulda

● JSSpec● Screw.Unit

● phpSpec● .net● erlang ● ...

Page 17: Intro a RSpec, BDD, webapps User Acceptance Testing

Livres pour 2008

Page 18: Intro a RSpec, BDD, webapps User Acceptance Testing

RSpecFramework de

BDD

Page 19: Intro a RSpec, BDD, webapps User Acceptance Testing

RSpec

Page 20: Intro a RSpec, BDD, webapps User Acceptance Testing

Anatomie d'une “spec”

describe Spec do before :each do @spec = Spec.new end

describe "après avoir été créée" do before :each do end it "devrait spécifier une seule classe" it "devrait avoir 0 comportements décrits" # ... end

describe "Lors de l'execution:" do # ... C

ompo

rtem

ents

Exemples

Page 21: Intro a RSpec, BDD, webapps User Acceptance Testing

exécutable

Pending:. Une spec, après avoir été créée devrait spécifier une seule classe (Not Yet Implemented). Une spec, après avoir été créée devrait avoir 0 comportements décrits (Not Yet Implemented)

Finished in 0.159 seconds

2 examples, 0 failures, 2 pending

Page 22: Intro a RSpec, BDD, webapps User Acceptance Testing

Anatomie d'un “exemple”

it "devrait spécifier une classe" do @spec.specified_class.should == Spec end

# Old School syntaxe TDD: it "devrait spécifier une classe" do assert_equals(Spec, @spec.specified_class) end

Page 23: Intro a RSpec, BDD, webapps User Acceptance Testing

it "devrait avoir 0 comportements décrits" do @spec.should have(0).behaviours end

# Old School syntaxe TDD: it "devrait avoir 0 comportements décrits" do assert_equals(0, @spec.behaviours.size) end

Plus de diff entre spec & code

Page 24: Intro a RSpec, BDD, webapps User Acceptance Testing

On écrit en langage “naturel” (VO)

“fluent interface” de Martin Fowler

'foo'.should == 'foo' ''.should be_empty 'foo with bar'.should include('with') 'http://21croissants.com'.should match(/http:\/\/.+/i) nil.should be_nil 100.should < 200 (200 - 100).should == 100

[1,2,3].should have(3).items [].should be_empty [1,2,3].should include(2)

Page 25: Intro a RSpec, BDD, webapps User Acceptance Testing

Tester en isolation avec les “mocks”

describe Person, "age" do

before :each do @bob = Person.new(:birth_date => "23/08/1975") end

it "should calculate age depending on birthday" do un_jour_sans_fin = Date.strptime('06/05/2008', '%d/%m/%Y') Time.should_receive(:now).and_return(un_jour_sans_fin) @bob.age.should == 32 end

end

Page 26: Intro a RSpec, BDD, webapps User Acceptance Testing

Exemple: EcoComparateur

PARIS → MARSEILLE

Page 27: Intro a RSpec, BDD, webapps User Acceptance Testing

EcoComparateur

En tant qu'eco-citoyen

Je veux connaître les emissions de CO2 d'un 4x4 pour un trajet A/R donné

Afin de réduire mon empreinte carbone

scénario 1

bla bla bla

scénario 1

bla bla bla

exemples

bla bla bla4x4Paris → Marseille

bla bla bla

Page 28: Intro a RSpec, BDD, webapps User Acceptance Testing

1er exemple

EcoComparateurwhen it calculates CO2emissions for a 'Paris-Marseille return', travelling with a SUV: should find 313kg of CO2

Page 29: Intro a RSpec, BDD, webapps User Acceptance Testing

Identifier les “classes”

EcoComparateur when it calculates CO2emissions for a 'Paris-Marseille return', travelling with a SUV: should find 313kg of CO2

Page 30: Intro a RSpec, BDD, webapps User Acceptance Testing

describe EcoComparateur do

describe "when it calculates CO2 emissions for a Paris-Marseille return," do

describe "travelling with a SUV:" do it "should find 313kg of CO2"

...

Conversion a RSpec

Page 31: Intro a RSpec, BDD, webapps User Acceptance Testing

“pending”

EcoComparateur when it calculates CO2 emissions for a 'Paris-Marseille return', travelling with a SUV:- should find 313kg of CO2 (PENDING: Not Yet Implemented)

Pending:EcoComparateur when it calculates CO2 emissions for a 'Paris-Marseille return', travelling with a SUV: should find 313kg of CO2 (Not Yet Implemented)

Finished in 0.053053 seconds

1 example, 0 failures, 1 pending

Page 32: Intro a RSpec, BDD, webapps User Acceptance Testing

describe EcoComparateur do before(:each) do @eco_comparateur = EcoComparateur.new end

describe "when it calculates CO2 emissions for a Paris-Marseille return," do describe "travelling with a SUV:" do before :each do @suv = mock("Car") @suv.should_receive(:kg_of_co2_per_km).and_return(20) end it "should find 313kg of CO2" do

@eco_comparateur.calculate_co2_emissions_for_an(@suv).travelling("Paris", "Marseille").

should == 313 end

...

Page 33: Intro a RSpec, BDD, webapps User Acceptance Testing

class EcoComparateur

def calculate_co2_emissions_for_an(vehicle) chain do travelling do |from, to| # TODO Implementation goes HERE! end end end

Implémentation du squelette

Page 34: Intro a RSpec, BDD, webapps User Acceptance Testing

EcoComparateur when it calculates CO2 emissions for a 'Paris-Marseille return', travelling with a SUV:- should find 313kg of CO2 (FAILED - 1)

1)'EcoComparateur when it calculates CO2 emissions for a 'Paris-Marseille return', travelling with a SUV: should find 313kg of CO2' FAILEDexpected "find 313 kg of CO2" but got nil./spec/eco_comparateur_spec.rb:23:

Finished in 0.186483 seconds

1 example, 1 failure

Failure

Page 35: Intro a RSpec, BDD, webapps User Acceptance Testing

On se “mock” des autres classes!

Comment calculer la distance entre Paris et Marseille?

On s'en mock!

Page 36: Intro a RSpec, BDD, webapps User Acceptance Testing

describe EcoComparateur do before(:each) do @geocoding_mock = mock("GeocodingHelper") @eco_comparateur = EcoComparateur.new(@geocoding_mock) end

describe "when it calculates CO2 emissions for a Paris-Marseille return," do before :each do @geocoding_mock.should_receive(:calculate_distance_in_km).

with("Paris", "Marseille").and_return(783) end

describe "travelling with a SUV:" do before :each do @suv = mock("Car") @suv.should_receive(:kg_of_co2_per_km).and_return(20) end it "should find 313kg of CO2" do @eco_comparateur.calculate_co2_emissions_for_an(@suv).

travelling("Paris", "Marseille").should find 313 }

end

it "should tell an inconvenient truth to the SUV owner ..."

Page 37: Intro a RSpec, BDD, webapps User Acceptance Testing

class EcoComparateur def initialize(geocoding_helper) @geocoding_helper = geocoding_helper end

def calculate_co2_emissions_for_an(vehicle) chain do travelling do |from, to| distance = geocoding_helper. calculate_distance_in_km(from, to) 2 * distance * vehicle.kg_of_co2_per_km end end end

Implémentation

Page 38: Intro a RSpec, BDD, webapps User Acceptance Testing

EcoComparateur when it calculates CO2 emissions for a 'Paris-Marseille return', travelling with a SUV:- should find 313kg of CO2

Finished in 0.061868 seconds

1 example, 0 failures

“success” !

Page 39: Intro a RSpec, BDD, webapps User Acceptance Testing

Avantages

Page 40: Intro a RSpec, BDD, webapps User Acceptance Testing

Design

● Le code de qualité est facile à tester● TDD = moins de code “mort”● Utilisation de “mocks” pour définir l'API

(Design incrémental)

Paris On Rail 2007 – Copyright (c) Garnier Jean-Michel. Licence: Creative Commons.

Page 41: Intro a RSpec, BDD, webapps User Acceptance Testing

Définition API

Page 42: Intro a RSpec, BDD, webapps User Acceptance Testing

Spécifications

Page 43: Intro a RSpec, BDD, webapps User Acceptance Testing

La doc des classes s'écrit toute seule...

Documentation exécutable

↔ Documentation toujours à jour !

Page 44: Intro a RSpec, BDD, webapps User Acceptance Testing

Tests d'acceptation

utilisateur

Page 45: Intro a RSpec, BDD, webapps User Acceptance Testing

Tests IHM webet d'acceptation utilisateur

Page 46: Intro a RSpec, BDD, webapps User Acceptance Testing

selenium-grid by Mr. Philippe Hanrigou

“grid” de machines avec selenium machines virtuels :

mac mini +Parrallel

SUPER RAPIDE! capture d'écrans (ALT + TAB)

Il y aussi : Watir / webrat

Page 47: Intro a RSpec, BDD, webapps User Acceptance Testing

RSpec

selenium-grid

selenium-core (js)

GRID de machines (physiques/virtuelles)

Page 48: Intro a RSpec, BDD, webapps User Acceptance Testing

Le format de “Story” de Dan North

Login d'un utilisateur

En tant qu'utilisateur

Je veux que l'accès à l'application nécessite un login / mot de passe

Afin de protéger mes données personnelles

Page 49: Intro a RSpec, BDD, webapps User Acceptance Testing

Critères d'acceptation: scénarios

Scenario 1: L'utilisateur se trompe de password

Etant donné que je suis ds la page de '/member/login'Lorsque je tape '[email protected]'

dans le champ 'email'Lorsque je tape 'xpday2008' dans le champ 'password'Lorsque je clique sur le bouton 'signin-form-submit'Alors je devrais voir le texte 'Linqia Member Log-in'Alors je devrais voir le message d'erreur

'Invalid login or password'

Page 50: Intro a RSpec, BDD, webapps User Acceptance Testing

Jean-Claude VanDamisation Scenario: 1. L'utilisateur se trompe de password

Given que je suis dans la page de '/member/login' When je tape '[email protected]'

dans le champ 'email' When je tape 'xpday2008' dans le champ 'password' When je clique sur le bouton 'signin-form-submit' Then je devrais voir le texte 'Linqia Member Log-in' Then je devrais voir le message d'erreur

'Invalid login or password'

Page 51: Intro a RSpec, BDD, webapps User Acceptance Testing

Binding texte / RSpec

Given que je suis dans la la page de '/member/login'

steps_for(:login) do

Given "que je suis dans la la page de '$path'" do |path| $browser.open path end .......end

Page 52: Intro a RSpec, BDD, webapps User Acceptance Testing

Binding (suite) When "je tape '$value' dans le champ '$field_name'"do|value, field_name| $browser.type field_name, value end When "je clique sur le bouton '$link'" do |link| $browser.click_and_wait link end

Then "je devrais voir le texte '$text'" do |text| text.should be_present end

Page 53: Intro a RSpec, BDD, webapps User Acceptance Testing

Demo

Page 54: Intro a RSpec, BDD, webapps User Acceptance Testing

54

Merci de votre attention!

Questions - Réponses

Page 55: Intro a RSpec, BDD, webapps User Acceptance Testing

Bonus

Page 56: Intro a RSpec, BDD, webapps User Acceptance Testing

Bonus (s'il reste du rab!)

L'équipe de RSpec: David, Aslak et Dan Autotest Couverture Heckle Mingle

Page 57: Intro a RSpec, BDD, webapps User Acceptance Testing

David Chelimsky

Page 58: Intro a RSpec, BDD, webapps User Acceptance Testing

Aslak Hellesøy (NO)

Page 59: Intro a RSpec, BDD, webapps User Acceptance Testing

Dan North

+ Brian Takita Dave Astels Steve Baker Luke Redpath

jbehave (2004) rbehave Intégration dans RSpec

Page 60: Intro a RSpec, BDD, webapps User Acceptance Testing

Autotest

● Problème: les specs s'executent pendant 10 min...● Solution: Autotest n'execute que les specs 

nécessaires

Notifications visuelles (plugins Growl, Notify,...) et sonores

http://ph7spot.com/articles/getting_started_with_autotest

Paris On Rail 2007 – Copyright (c) Garnier Jean-Michel. Licence: Creative Commons.

Page 61: Intro a RSpec, BDD, webapps User Acceptance Testing

Garantir la couverture avec rcov

● sudo gem install rcov● rake spec:rcov

http://eigenclass.org/hiki.rb?rcov

Paris On Rail 2007 – Copyright (c) Garnier Jean-Michel. Licence: Creative Commons.

Page 62: Intro a RSpec, BDD, webapps User Acceptance Testing

Couverture détaillée

Page 63: Intro a RSpec, BDD, webapps User Acceptance Testing

Heckle

Page 64: Intro a RSpec, BDD, webapps User Acceptance Testing

Mingle