Ultra-tiny given-when-then DSL-snippet

Jeg har testet diverse TDD/BDD-rammeverk de siste månedene (bl.a. machien specification og tinyBDD), og eksperimentert endel med hvordan jeg kan skrive tester/spesifikasjoner som dokumenterer koden best mulig. Dette har resultert i at jeg ikke bruker noe spesielt rammeverk i det hele tatt, men bare bruker deskriptive navn og et generelt given-when-then formular.

Mine tester har en stund nå sett ut omtrent som dette:

        [Test]

        public void Stupid_car_start_1()

        {

            Given_transmission_is(manual);

            Given_transmission_is_in(first_gear);

            Given_clutch_pedal_is(not_engaged);

            When_key_is_turned();

            Then_car_should_jump_forward();

            Then_engine_should_be_dead();

        }

Det virker litt teit å si given tre ganger på rad. Alternativt kunne given nummer to og tre i stedet begynt med “And_”, og det samme kunne jeg gjort med Then_engine_is_dead(). Det er derimot et problemer med den måten å gjøre det på; ofte vil den metoden som er given nummer 3 i én test plutselig bli den eneste given i en annen test, og da kan den ikke hete noe med “And”.

Et annet problem er at det som er en “When” i én test kan være kjekk å bruke som en “Given” i neste test. For å løse dette problemet legger jeg til et lite sett med properties i test-klassen:

        #region Really tiny BDD DSL / Syntactic sugar

        protected CarStartTests Given { get { return this; } }

        protected CarStartTests When { get { return this; } }

        protected CarStartTests Then { get { return this; } }

        protected CarStartTests and { get { return this; } }

        #endregion

Her ser du hvordan den forrige testen blir seende ut ved å bruke de nye propertiene:

        [Test]

        public void Stupid_car_start_2()

        {

            Given.transmission_is(manual);

            and.transmission_is_in(first_gear);

            and.clutch_pedal_is(not_engaged);

            When.key_is_turned();

            Then.car_should_jump_forward();

            and.engine_should_be_dead();

        }

Men nå står jeg også mye mer fritt til å trikse å mikse med metodene og variablene i test-klassen, samtidig som jeg beholder et flytende og naturlig språk. Samme testen kunne f.eks. lett se ut som dette:

        [Test]

        public void Stupid_car_start_3()

        {

            Given.vehicle.Transmission = manual;

            and.vehicle.Transmission.SetGear(first);

            and.vehicle.Clutch.ChangeState(not_engaged);

            When.key.Turn();

            Then.car_jump_counter.should_be(1);

            and.vehicle.Engine.State.should_be(dead);

        }

I realiteten blir det som regel en blanding av de to fremgangsmåtene: Givens skjuler ofte mye, som f.eks. oppsett av mocks/fakes, og beholdes som metoder. Thens på den andre siden er som oftest minst like lesbare om de er tester direkte på en eller annen variabel brukt for å “sanse” korrektheten av testen/spesifikasjonen. Kombinert med et sett med fluent asserts (som du finner i coreTDD) blir en sjekk av en variabel like lesbar som et metodenavn.

Nedenfor er en Visual Studio snippet-fil jeg har definert for å enkelt kunne inserte de fire BDD-propertiene i nye testklasser. Hvis du lagrer XML’en med navnet bdd.snippet under “My Documents\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets”, så vil du kunne bruke den ved for eksempel å skrive “bdd” i koden din (uten hermetegnene altså..) og trykke TAB to ganger.

    1 <?xml version="1.0" encoding="utf-8" ?>

    2 <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

    3     <CodeSnippet Format="1.0.0">

    4         <Header>

    5             <Title>Given-When-Then Syntax Sugar</Title>

    6             <Shortcut>bdd</Shortcut>

    7             <Author>http://blog.kjempekjekt.com</Author>

    8             <Description>Provides a really tiny dsl for doing bdd.</Description>

    9         </Header>

   10         <Snippet>

   11             <Declarations>

   12                 <Object Editable="false">

   13                     <ID>ClassName</ID>

   14                     <Function>ClassName()</Function>

   15                 </Object>

   16             </Declarations>

   17             <Code Language="CSharp">

   18                 <![CDATA[

   19                   #region Really tiny BDD DSL / Syntactic sugar

   20                   protected $ClassName$ Given { get { return this; } }

   21                   protected $ClassName$ When { get { return this; } }

   22                   protected $ClassName$ Then { get { return this; } }

   23                   protected $ClassName$ and { get { return this; } }

   24                   #endregion

   25                 ]]>

   26             </Code>

   27         </Snippet>

   28     </CodeSnippet>

   29 </CodeSnippets>

Hvis du finner noe mindre BDD-rammeverk enn dette så må du gi meg et vink ;)

Kategorier: Software/verktøy, Testing / TDD.
RSS feed for kommentarene. Tilbaketråkk.

2 kommentarer til “Ultra-tiny given-when-then DSL-snippet”

  1. perottobc Says:

    For java vil kanskje rammeverket se slik ut:

    public class ScenarioSupport {
    T gitt = (T) this;
    T og = (T) this;
    T naar = (T) this;
    T saa = (T) this;
    }

    hvor testklassen da arver fra ScenarioSupport, se eksempel her: http://bdoc.googlecode.com/svn/trunk/bdoc-examples/pensjonsberegning/src/test/java/pensjonsberegning/TestAlderspensjonBehaviour.java

    Er nok noe som jeg må putte inn støtte for i bdoc – http://bdoc.googlecode.com

    Veldig bra blog!
    /perottobc

  2. Torbjørn Says:

    PS: Jonas Follesø har laget en variant av DSL’en som bruker en baseklass: https://gist.github.com/406014

Skriv en kommentar

Tillatte tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Einar W. Høst: Det er jo læringen som gjør det morsomt! Se også http://norvig.com/21-days...

Pagliacci: OBS! tl;wr. Det er vel akuratt det jeg sliter med med min læring innenfor pr...

Torbjørn: La oss anta to ulike definisjoner av Template Method pattern - de to ytterpunkte...

Lars-Petter: Hei igjen. Siden du inviterer til å ta diskusjonen i bloggen, og har tatt deg t...

Torbjørn: Lars-Petter: Det er én måte å se det på. Det er absolutt fortsatt Template M...

Lars-Petter: Hei. Har du ikke i prinsippet her gått over fra Template Method (arv) til Strat...

Christian Abildsø: I alle fall i C#, så føles dette som kode som blir mer fleksibel men vanskelig...

Torbjørn: Hei Henrik, og takk for tilbudet. Ble oppmerksom på Rasberry Pi for under en uk...

Henrik Sandaker Palm: Ang. større hobby prosjekt. Du er som er en slik rakker på programmering har j...

Øivind Nilsen: Slutt å bruke mobilnummeret mitt som eksempel !...

Mulig relaterte linker

 Hold deg oppdatert

Søk i bloggen

Ferske innlegg

  • En historie om programmering
  • Template Method del 4: Multippel arv
  • Template Method Intermesso
  • Template Method del 3: Bare funksjoner
  • Kategorier

  • .net ninja (37)
  • Bøker (17)
  • Diverse prosjekter (35)
  • DSL (10)
  • Erlang (10)
  • F# (5)
  • Hardware (1)
  • Jobb (77)
  • Julekalender (51)
  • kjempekjekt.com (23)
  • LISP/Clojure (33)
  • NNUG / community (60)
  • O/RM & databaser (10)
  • Off topic (116)
  • OO-design/clean code (30)
  • Podcasts (14)
  • Polyglot (77)
  • Ruby (27)
  • Silverlight / RIA (3)
  • Software/verktøy (20)
  • Softwareutvikling (21)
  • Testing / TDD (30)
  • the contiki strip (13)
  • User experience (3)
  • WCF (3)
  • Webutvikling (32)
  • WPF (9)
  • WTF (12)
  • Last ned Wallpaper

    Programmeringsbloggens tøffe skrivebordsbakgrunn med snippets fra ulike språk laster du ned her!

    Abonner via epost

    Om du vil kan du få alle nye blogposter tilsendt til din epost. Abonner nå, det er kjempeenkelt!

    Meta