Poster taggade med ‘test’

Sida 1/2:12

Efter att du har läst Martins artikel om Scala och SBT så kanske du känner dig lite sugen att börja koda i Scala, men inte riktigt vet var du skall börja. Jonas Bonér var hos Cygni och talade för ett tag sedan och nämnde då att det kan vara en bra början att skriva sina testfall i Scala för att komma igång och lära sig språket. Scala erbjuder dessutom väldigt trevliga testramverk, som kan underlätta din vardag. Jag kommer förutsätta att du idag har ett mavenprojekt med javakod och eventuella befintliga tester i java.

Första steget är att lyfta in Scalas API, JUnit 4 (om du inte redan kör det) och ett testramverk. Jag tänkte använda ScalaTest. För att göra det så lägger vi till följande beroende i pom.xml

<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-library</artifactId>
    <version>2.9.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.scalatest</groupId>
    <artifactId>scalatest_2.9.1</artifactId>
    <version>1.6.1</version>
    <scope>test</scope>
</dependency>

Sedan behöver vi säga till Maven att också kompilera och köra testfall som ligger i biblioteket src/test/scala, så då lägger vi till tre plugins.

maven-scala-plugin ansvarar för att kompilera scalakoden till bytekod.

<plugin>
    <groupId>org.scala-tools</groupId>
    <artifactId>maven-scala-plugin</artifactId>
    <version>2.15.0</version>
    <executions>
        <execution>
            <goals>
                <goal>testCompile</goal>
            </goals>
            <configuration>
                <args>
                    <arg>-make:transitivenocp</arg>
                    <arg>-dependencyfile</arg>
                    <arg>${project.build.directory}/.scala_dependencies</arg>
                </args>
            </configuration>
        </execution>
    </executions>
</plugin>

maven-surefire-plugin är den som kör testerna – om du redan har tester i projektet så har du redan lagt till den här pluginen och behöver då bara utöka den att också inkludera filer som heter **/*Spec.*.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <useFile>false</useFile>
        <disableXmlReport>true</disableXmlReport>
        <includes>
            <include>**/*Spec.*</include>
            <!-- För att hantera existerande tester -->
            <include>**/*Test.*</include>
        </includes>
    </configuration>
</plugin>

build-helper-maven-plugin lägger till källkodsmappar till kompilering, eftersom Maven från början bara hanterar en källkodsmapp för implementationskod (src/main/java som standard) och en för test (src/test/java som standard).

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>generate-test-sources</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>src/test/scala</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

Ok, nu behöver vi bara skapa mappen src/test/scala och sedan kan du börja koda!

Om du vill kan du stanna här. Nu kan du skriva testklasser i Scala, annotera metoderna med JUnits @Test och köra på som vanligt. Det du vinner är att du får tillgång till Scalas syntax och konstruktioner och att du kan lära dig i en bekant miljö.

Det andra alternativet är att du också börjar titta på vad Scalas testramverk kan erbjuda. I grunden är det inte så stor skillnad, men rent syntatiskt och kanske också tankemässigt så är det lite annorlunda. ScalaTest har stöd för BDD – Behaviour Driven Development. Tanken är att varje test är en beskrivning av en funktion/ett beteende som en roll skall uppfylla. Rollen tar sedan formen av en eller möjligtvis flera klasser. Tack vare att Scalas syntax går att det skriva ganska koncisa specifikationer, nästan som rena texttester för att beskriva beteendet som förväntas.

Vi börjar med att skriva en första specifikation, som vår applikation skall uppfylla.

@RunWith(classOf[JUnitRunner])
class MyApplicationSpec extends FlatSpec with MustMatchers {

  "My application" must "convert a string to hex values" in {
  }

}

Det här är ett komplett test, även om det inte gör något just nu – kroppen på specifikationen är tom. Om jag vill kan jag lämna det tomt och fylla på senare, eller så gör jag det lite tydligare att jag inte är klar med testet. Då skriver vi om det såhär

@RunWith(classOf[JUnitRunner])
class MyApplicationSpec extends FlatSpec with MustMatchers {

  "My application" must "convert a string to hex values" in (pending)

}

Väldigt tydligt och förklarande, eller hur? Ponera att jag skapar en klass som kan konvertera en sträng till hexadecimala värden (wow!). Då kan testkoden se ut som följande

@RunWith(classOf[JUnitRunner])
class MyApplicationSpec extends FlatSpec with MustMatchers {

  "My application" must "convert a string to hex values" in {
    val app = new MyApplication()
    app.convert("The donkey makes a left turn. I observe.") must equal ("54686520646f6e6b6579206d616b65732061206c656674207475726e2e2049206f6273657276652e")
  }

}

Klassen MyApplication är fortfarande skriven i Java, men jag testar den från Scala. Nyckelordet ”must” kommer från en trait i ScalaTest som heter MustMatchers. Det går också att använda ShouldMatchers, enda skillnaden är terminologin – must eller should, vilket du tycker om bäst.

Genom att fylla på med test av det här slaget så får du en ganska tydligt dokumentation vad du faktiskt förväntar dig av dina roller/klasser. Då slipper du en massa kommentarer i koden och/eller testmetoder som döpts ”testShouldConvertStringToHexValue” eller liknande. Enkelt och snyggt!

Vill du använda mockobjekt i din scalakod så kan du antingen köra på någon av de vanliga javabiblioteken (JMock, EasyMock, Mockito), eller så kan du prova Borachio som är skrivet i Scala.

Idag tillhör det vanligheterna att du som utvecklare skriver automatiska test för din kod. Många projekt använder sig av olika former av dependency injection eller har beroenden mellan klasser som gör det krångligt att testa varje del för sig. Detta leder ibland till att tester omfattar stora delar att systemet (mer åt integrationstestning), vilket i sin tur leder till att det blir krångligt att underhålla och svårt att felsöka. Vissa framhåller att större tester gör dem robusta – de går inte ”sönder” lika lätt om något ändras inne i implementationen – men jag föredrar en robust implementation framför ett robust test, om ni förstår vad jag menar. Ju mindre del som varje test måste verifiera desto bättre – själva grunden för enhetstestning.

Hur bryter du isär koden så att det går att testa separat då? Jo, här kommer då mockobjekt in i bilden. Med hjälp av dessa syntetiska objekt som representerar dina kodberoenden så kan du isolera den kod som du vill testa, utan att råka ut för NullPointerException. Termen myntades (iallafall för den bredare publiken) av några utvecklare på en extreme-programming-konferens år 2000, där de också presenterade ett första ramverk för detta.

Ponera följande kodexempel (där Courier är ett interface)

class AwesomeApp {
   Courier courier;
   public Content checkPacket() {
      if ( !courier.hasNewPacket() ) {
         throw new NoNewPacketAsFarAsWeCouldSeeException();
      }
      Packet packet = courier.getNewPacket();
      Content content = packet.open();
      return content;
   }
   public void setCourier(Courier courier) {
      this.courier = courier;
   }
}

Om jag skriver följande test, så ramlar jag oundvikligen ned i NullPointerException-gropen eftersom courier är null i AwesomeApp.

class AwesomeAppTest {
   public void testCheckPacket() {
     AwesomeApp app = new AwesomeApp();
     Content content = app.checkPacket();
     // Assert content
   }
}

Vad göra? Lösningen är då alltså att använda ett mockobjekt. Antingen kan jag skriva en egen klass som implementerar interfacet Courier, samt hantera alla testvillkor som objekt av den klassen måste uppfylla, eller så använder jag ett färdigt ramverk. Valet känns lätt. Genom att välja ett färdigt ramverk så slipper jag en del underhåll och får samtidigt ett färdigt utvecklingsmönster att följa – annars kan det lätt bli att varje utvecklare i ett projekt gör på sitt eget sätt.

De vanligaste ramverken som används idag skulle jag säga är EasyMock, JMock samt Mockito. De är alla likvärdiga i funktionalitet och även om konstruktionerna kan skilja sig lite åt så är grunden densamma. Jag har också stött på ett ramverk som heter RMock, men det är gammalt och stöder inte ens Java 5 Generics, så jag tar inte upp det här. Här nedan följer några exempel på hur AwesomeAppTest skulle skrivas med alla tre ramverken, så att läsaren kan jämföra.

JMock

JMock har funnits länge och är en vidareutveckling av det ramverk som presenterades på extreme-programming-konferensen jag nämnde ovan. Version 1 var lite knölig att använda, eftersom metodmatchning gjordes med strängar vilket gav problem vid refaktorisering. Detta är dock löst i version 2 som sedan länge är den som gäller.

class AwesomeAppTest {
   @Test
   public void testCheckPacket() {
      // JMock-specifik klass
      Mockery mockery = new Mockery();
      // Här skapar vi vårt mockobjekt med JMock
      Courier courier = mockery.mock(Courier.class);

      // Förväntat returvärde från testade koden
      Content expectedContent = new Content();
      // Returvärden från mitt mockobjekt
      Packet anyPacket = new Packet(expectedContent); 

      // Definiera våra förväntningar, ett anrop till
      // courier.hasNewPacket() och ett till
      // courier.getNewPacket() samt deras returvärden
      mockery.checking(new Expectations() {{  

         oneOf(courier).hasNewPacket();
         will(returnValue(true));

         oneOf(courier).getNewPacket();
         will(returnValue(anyPacket)); 

      }});

      AwesomeApp app = new AwesomeApp();
      // Här sätter vi vårt mockobjekt som
      // beroende till AwesomeApp
      app.setCourier(courier);
      Content content = app.checkPacket();

      // Kontrollera att resultatet är det förväntade
      assert content == expectedContent;

      // Verifiera att förväntningarna inträffade
      mockery.assertIsSatisfied(); 

   }
}

EasyMock

EasyMock är också ganska gammal i gemet och var tidig med att ha stöd för refaktorisering.

class AwesomeAppTest {
   @Test
   public void testCheckPacket() {
      // Här skapar vi vårt mockobjekt med hjälp av EasyMock
      Courier courier = EasyMock.createMock(Courier.class); 

      // Förväntat returvärde från testade koden
      Content expectedContent = new Content();
      // Returvärden från mitt mockobjekt
      Packet anyPacket = new Packet(expectedContent); 

      // Definiera våra förväntningar, ett anrop till
      // courier.hasNewPacket() och ett till
      // courier.getNewPacket()  samt deras returvärden
      EasyMock.expect(courier.hasNewPacket()).andReturn(true);
      EasyMock.expect(courier.getNewPacket()).andReturn(anyPacket);

      // Sätt EasyMock i replay-läge,
      // där förväntningarna skall uppfyllas
      EasyMock.replay(courier); 

      AwesomeApp app = new AwesomeApp();
      // Här sätter vi vårt mockobjekt som
      // beroende till AwesomeApp
      app.setCourier(courier);
      Content content = app.checkPacket();

      // Kontrollera att resultatet är det förväntade
      assert content == expectedContent;

      // Verifiera att förväntningarna inträffade
      EasyMock.verify(courier);
   }
}

Mockito

Mockito är i praktiken en vidareutveckling av EasyMock, från början en fork som nu har skrivits om helt. Tack vare arvet är dock syntaxen väldigt lik.

class AwesomeAppTest {
   @Test
   public void testCheckPacket() {
      // Här skapar vi vårt mockobjekt med hjälp av Mockito
      Courier courier = Mockito.mock(Courier.class); 

      // Förväntat returvärde från testade koden
      Content expectedContent = new Content();
      // Returvärden från mitt mockobjekt
      Packet anyPacket = new Packet(expectedContent); 

      // Definiera våra förväntningar, ett anrop till
      // courier.hasNewPacket() och ett till
      // courier.getNewPacket() samt deras returvärden
      Mockito.when(courier.hasNewPacket()).thenReturn(true);
      Mockito.when(courier.getNewPacket()).thenReturn(anyPacket);

      AwesomeApp app = new AwesomeApp();
      // Här sätter vi vårt mockobjekt som
      // beroende till AwesomeApp
      app.setCourier(courier);
      Content content = app.checkPacket();

      // Kontrollera att resultatet är det förväntade
      assert content == expectedContent;

      // Verifiera att förväntningarna inträffade
      Mockito.verify(courier);
   }
}

Summering

Som ni ser skiljer det inte mycket mellan ramverken, det som kanske framträder mest är att EasyMock har ett steg extra – där EasyMock sätts i ”replay”-läge – mot både JMock och Mockito. Alla tre har stöd för att verifiera att metodanrop sker i rätt ordning, verifiera argument etc. Det går också att sätta mjukare förväntningar, såsom att en metod skall anropas en eller flera gånger, att man inte bryr sig om anrop och returvärde på ett visst objekt osv.

Vilket ramverk du skall välja är mer upp till personlig smak än funktionalitet. I de flesta fall kanske du sitter i ett projekt som redan använder ett mockramverk och då har du förhoppningsvis fått en lite bättre förståelse för vad ramverket gör.

Som avslutning kan jag rekommendera lite läsning från utvecklarna som myntade begreppet mockobjekt. Du hittar det på www.mockobjects.com – läs gärna deras papper som ligger som länkar i högerkolumnen på den sidan.

Du har just klickat dig in på den första delen i min samling artiklar om Python – detta dynamiska högnivåspråk som både jag, många andra utvecklare samt organisationer som Google och YouTube tycker är grymt att utveckla i. I de kommande artiklarna tar jag upp bakomliggande filosofier, egenskaper hos språket, hantering av datatyper och allmänna tips och tricks som kan vara till hjälp för dig som är ny i språket. Läs mer >>

JAXB betyder Java Architecture for XML Binding och används för att konvertera POJOs till XML och vice versa. Metoden för att konvertera en POJO till XML kallas för marshalling eller serialisering. Det motsatta, det vill säga att konvertera från XML till en POJO, kallas för unmarshalling eller deserialisering.

I denna artikel visar jag hur man kan använda JAXB för serialisering/deserialisering på ett enkelt sätt med hjälp av ett enhetstest. Exemplet finns att hämta på GitHub – https://github.com/cygni-stacktrace/jaxb-sample.

Läs mer >>

Cygni är ett IT-konsultbolag med drygt 40 anställda som grundades 2006. Vi erbjuder expertis inom agil systemutveckling på moderna plattformar. Den genomsnittlige Cygnikonsulten är 35 år, civilingenjör i datateknik och har 12 års professionell erfarenhet av systemutveckling. Men den främsta styrkan sitter varken i erfarenhet eller utbildning. Den sitter i engagemanget att ständigt vilja utvecklas och bli en bättre konsult.

Med en stadig förankring i vår systemutvecklingsexpertis kan Cygni utföra konsultuppdrag i alla branscher i behov av avancerat systemstöd. Cygnis kunder finns idag främst inom finans, media, retail, telekom och spel.

Det som utmärker Cygni är vår selektiva rekryteringsprocess. Vi sätter aldrig kvantitativa tillväxtmål eftersom de skulle kunna komma i konflikt med våra kvalitetsmål. Sedan starten 2006 har Stockholms främsta konsulter inom agil systemutveckling handplockats, bland annat genom branschens tuffaste tekniktester. Det har gett oss en stark företagsgemenskap, obefintlig personalomsättning, nöjda kunder och ett mycket välfungerande internt kompetensutbyte.

Cygnis kontor är centralt beläget på Sturegatan 34 i Stockholm med utsikt över Humlegården. De flesta uppdrag som Cygni utför är på plats hos våra kunder i Stockholmsområdet men kontoret fungerar som en naturlig samlingsplats för konsultmöten, afterwork och andra aktiviteter.

Karta till Cygnis kontor
Cygni
Sturegatan 34
114 36 Stockholm 

Tel: 08 459 93 30
E-post: info@cygni.se

Cygni sponsrar BRIS i deras arbete att stödja utsatta barn. Under 2012 är Cygni ett av BRIS guldföretag.

BRIS

Följ oss via LinkedIn, Twitter eller Facebook

Cygni på LinkedIn

Twitter

När man börjar utveckla i Scala dröjer det inte länge innan man behöver ett byggverktyg. Maven kommer med fullt javastöd  men för att kompilera Scala behövs maven-scala-pluginen. Det  gör att man börjar undra om det finns ett byggverktyg med fullt inbyggt stöd för Scala och det gör det, Simple Build Tool, eller SBT. På code.google.com finns SBT att ladda ner och bra engelsk dokumentation för installation och handhavande.

SBT liknar Maven väldigt mycket; samma konvention för hur filerna ska organiseras, de flesta av Mavens kommandon har direkta motsvarigheter i SBT. Så istället för mvn compile skriver man sbt compile.

SBT kan använda Mavens repositories, till och med Mavens pom.xml för beroendehantering. Det gör att det är väldigt enkelt att testa SBT i ett befintligt Maven-projekt.

Så vilka fördelar har SBT framför Maven, förutom att kompilera både scala- och javakod utan plugin-konfiguration?
Läs mer >>

Tänkte tipsa om ett trevligt verktyg vid namn Ack som jag hittade häromdagen. Det är en ”bättre version” av det gamla klassiska grep-kommandot.

Ponera följande, om du vill hitta alla förekomster av strängen ”Test” i dina javafiler men hoppa över alla filer i dina dolda subversion-kataloger kan du köra följande grep-kommando:

grep Test $(find . -name '*.java' | grep -v .svn)

Med verktyget ack ser kommandot ut så här:

ack-grep --java Test

Lite trevligare tycker jag. Ack stöder en rad filtyper såsom perl, java, C# etc och installationen är smidig – i alla fall om du kör Ubuntu. Dessutom är output:en från kommandot lite lättare att tolka…

Kolla in Ack vetja!

EJB 3.0 är den nu gällande versionen av Java Enterprise Beans(EJB) arkitekturen som ingår i Java EE 5. Syftet med EJB 3.0 är att förbättra arkitekturen för EJB och minska komplexiteten för utvecklaren av EJB applikationer. Detta innebär tex följande förbättringar:

  • Annoteringar, det finns ett gäng med annoteringar som man kan använda sig utav för att förenkla arbetet. Dessa annoteringar minskar antalet klasser och interface som man måste skapa och man behöver inte skapa någon deployment descriptor (om man inte vill).
  • Defaulta värden, man skall slippa specifiera en massa vanliga förväntade beteenden och krav från EJB-containern.
  • Inkapsling av beroenden och JNDI åtkomst via annoteringar och dependency injection (DI)
    Businessinterfacet för en sessionsböna kan vara ett vanligt Java-interface, det behöver inte vara av typen EJBObject, EJBLocalObject eller javax.rmi.Remote
  • Home-interfacet behövs inte längre för sessionsbönor.
  • Minskning av krav av användning av checked exceptions
  • En interceptor funktionalitet finns för sessions- och message-driven-bönor.
  • Entitetsbönor har fått en helt egen specifikation, Java Persistence API (JPA), är numera vanliga POJO’s.

Det finns ett par olika typer av EJB:er, sessionsbönor och message-driven-bönor. Sessionsbönorna kommer i två olika smaker, Stateless och Stateful. Entitetsbönorna har ju som sagt ersatts med JPA entiteter. Jag tänkte gå igenom dessa med små korta exempel. Läs mer >>

Detta inlägg ingår i serien Spring från början och kommer att behandla Springs stöd för Hibernate. Vi kommer inte att gå närmare in på vad Hibernate är och gör utan koncentrera oss på vad Spring kan hjälpa oss med och hur man kan jobba med HibernateTemplate och andra centrala klasser i modulen spring-orm. ORM står för Object Relational Mapping och modulen spring-orm innehåller dessutom stöd för JPA, TopLink och iBATIS.
Läs mer >>

Sida 1/2:12