Typ-smocka med Mockito

Jag stötte på en riktig fuling idag när jag skulle skriva ett test likt det nedan. Hittade “lösningen” på mailinglistan efter att ha läst ett par buggar/feature requests.

Som jag förstår det går det inte att lösa pga Javas Type Inference i metodanrop. I exemplet nedan kan raden med when aldrig fungera utan man får gå på doReturn istället.

package demo;
 
import static java.util.Arrays.asList;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
 
import java.util.Collection;
 
import org.junit.Test;
 
public class GenericCollectionStubTest {
 
    @Test
    public void onGoingStubFails() {
        Car bmw = mock(Car.class);
        Reseller reseller = mock(Reseller.class);
        Collection cars = asList(bmw);
 
        //when(reseller.getModels()).thenReturn(cars);
 
        doReturn(cars).when(reseller).getModels();
    }
}

Raden med when misslyckas med följande meddelande:

The method thenReturn(Collection<capture#1-of ? extends Vehicle>) in the type OngoingStubbing<Collection<capture#1-of ? extends Vehicle>> is not applicable for the arguments (Collection<capture#2-of ? extends Vehicle>)

Ämnen för Java-TDD

Tittar på att gå ett steg längre med TDD-workshops och lämna de grundläggande ämnena. Följande har efterfrågats:

  • testning med/av legacy code
  • vad är bra respektive dåliga test
  • funktionell eller acceptansdriven testning (ATDD)
  • beteende driven utveckling (BDD)

Egna saker jag själv skulle vilja gräva lite mer i och ägna ett par timmar åt:

  • hamcrest (matchers)
  • dotmesh (methods)
  • making EasyMock suck less
  • making Mockito suck
  • easyB
  • Fitnesse

I allmänhet så saknar jag en diskussion om hur lättredigerade test (wiki?) versionshanteras ihop med koden de testar eller är skrivna mot. Detta är ju högst intressant när man går in och gör en hot-fix för en produkt som rört sig mycket under ett år, och en kund som har produkten i drift sedan ett drygt år tillbaka vill sin fix. Hur kör man samma testsvit som man hade för ett år sedan på ett enkelt sätt? Hur är egentligen inte svårt. Jag har bara inte sett många bra lösningar, ännu. TextTest, xUseCase och liknande plain text-ramverk är en bra lösning. Frågan är bara om testen är tillräckligt tillgängliga för ATDD – hur får man kunden att känna att det är hans/hennes test?

Eclipse och TDD

Eclipse är ganska svagt utrustat från start för att köra TDD effektivt. Det verkar inte komma ifrån att code completion måste utföras med CTRL+mellanslag – här kommer IntelliJ för alltid lysa med sin vackerhet (där mellanslag eller tab är “markören” som kollar om den skall auto-complete:a).

Favorites

Följande klasser är bra att peta in i varje workspace Window » Preferences » Java » Editor » Content Assistant » Favorites:

  • java.util.Arrays.*
  • java.util.Collections.*
  • org.junit.Assert.*
  • org.mockito.BDDMockito.*
  • org.mockito.Matchers.*
  • org.mockito.Mockito.*
  • org.mockito.MockitoAnnotations.*

Templates

Börja med att ta bort  alla SWT, ta bort test för JUnit 3.

WORK IN PROGRESS!

before

${staticImport:importStatic('org.mockito.MockitoAnnotations.initMocks')}
@${beforeAnnotation:newType(org.junit.Before)}
public void ${setup}() throws Exception {
  initMocks(this);
  testee = new ${cursor};
}

Det är givetvis trevligare med @RunWith(MockitoJUnitRunner.class). MoreUnit kan hjälpa till med att sätta upp detta.

mock

@Mock private ${type} ${mock};

bdd – BDD-ish Test

@Test public void statement() throws Exception {
    given(${mock}.${method}).willReturn(${value});
 
    // WHEN ${when}
    ${testee}.${act};
 
    // THEN ${then}
    verify(${mock}).${method}(${arguments});
}

tdd – TDD test

@Test public void statement() throws Exception {
    // Arrange
    // Act
    // Assert
}

JDojo – TDD i fem steg

Genom mitt jobb har jag haft det stora nöjet att få hålla ett antal kodningstillfällen som “lanserats” under namnet JDojo@Gbg. Det var tack vare Emily Bache som detta kom till stånd och när hon nu seglade vidare mot Ruby-landet så har jag tagit över vid rodret och det hela har, mer eller mindre, näst intill formaliserats i en serie beprövade övningar i olika ämnen (kurspaket om 10 timmar skulle säkert någon vilja kalla det).

Det som började med en ambition om att sprida TDD och andra goda principer för “hantverksyrket” programmering snappades ganska snabbt upp på olika arbetsplatser och till dags dato har snart fem olika grupper/JDojos genomförts (med fler i uppstartningsfasen) och detta är en liten sammanfattning (reflektion/retrospektiv) av hur det sett ut hittills.

Ämnen som avhandlats

Utan omsvep så har vi under dessa JDojos avhandlat följande ämnen, med – för alla deltagare – mycket givande diskussioner.

Testdriven utveckling

Ett ämne som försvaras ganska brett (värdet av en bra testsvit) men “lärs ut” ganska smalt. Under SDC2010 i en fishbowl-debatt på temat “Should every proffessional developer practice TDD” var de flesta överens om “nja, det viktiga är en bra testsvit, men hur man kommer fram till den är inte givet” medan Michael Feathers mer var av åsikten “outside of Sweden, this is more or less concidered the solution”.

The Solution, med “test first”, red-green-refactor, etc lärs ut eller gås igenom i denna första övning.

Clean Code

Efter en introduktion till TDD och själva processen tar vi upp saker som “test backlog” och fokuserar ännu mer på refactor-steget och diskuterar (och deltagarna på något sätt enas om) definitionen av Clean Code. Ett antal best practices tas fram och även om det låter som ett tunt ämne så är diskussionerna här alltid rika, nyanserade och har beskrivits som “mycket värdefulla”.

Objektorienterad utveckling och TDD

Nästa steg i utforskandet av TDD har varit att titta på vad som händer när man tar steget från “enklare” imperativ/funktionell programmering och in i det objektorienterade landskapet. Med rätt uppgift och lagom dos moderering tyder ett mönster fram som i princip går ut på mycket fokusskifte mellan klasser. Ganska snart i retrospektiven brukar ett samtal kring kring inside-out, bottom-up och top-down dyka upp.

Mockist vs Stubborn Approach

Efter att ha känt på det dyra med att skifta fokus fram och tillbaka med TDD och OO bjuder nästa övningstillfälle på möjligheten att med hjälp av mockning (Mockito) bibehålla fokus på “en klass i taget” och i större utsträckning kunna fokusera på interaktionen, gränssnitt och enskilda klassers roller. Syftet med mockning, och när det är lämpligt att mocka, blir tydligt i jämförelse med föregående övning.

Behaviour Driven Development

Den femte övningen har antingen fokuserats mot BDD om det funnits intresse för detta. Fokus har legat på formen av GIVEN, WHEN, THEN och det somliga kallar ryska dockor och andra utifrån-in eller outside-in.

Legacy Code / befintlig kod

Ett annat efterfrågat ämne är hur man inför TDD-tänk kring kod som inte redan täcks av test, eller kanske inte är testbar (eller iaf svårtestad). Michael Feathers bok “Working Effectively with Legacy Code” demonstrerar detta på ett utomordentligt bra sätt och i denna övning har vi tagit kundens befintliga kodbas (om möjligt/lämpligt) och bearbetat den för att uppnå olika mål.

Mer (än) rubriker

Givetvis avhandlas många olika aspekter av systemutveckling parallellt, t ex Characteristics of a Good Test, Enough Tests? 3A vs BDD? Baby Steps, TDD vs Traditional Testing, …

Workshop i Eclipse som mjukstart

Vid ett par tillfällen har vi inlett med en workshop om effektiv utveckling i Eclipse. Detta har gett utvecklarna en möjlighet att känna på Dojo-ledaren, och omvänt en möjlighet att anpassa materialet efter gruppens förkunskaper och önskemål.

Formen för övningstillfällena

Vi har i huvudsak använt Eclipse, JUnit, Mockito och FitNesse. De 120 minutrarna används effektivt med en introduktion av dagens övning och ibland av det ämne man skall behandla – värdet av självinsikt får vägas in här och anpassas efter gruppen. Ca 90 minuter används till utförandet av övningen och avslutas med en en lagom kort retrospektiv där övning, erfarenheter och reflektioner tas upp och blandas friskt.

Vad är en Coding Dojo?

Dojo är namnet på lokalen där bl a olika kampsporter utövas, t ex Karate. 2005 lanserades termen “Coding Dojo” (eller Coders’ Dojo) där principen är att man upprepat utför vissa övningar, så att man genom repetition övar upp olika färdigheter/kunskaper så att när man behöver dem i “skarpt läge” kan man med lätthet kan agera på ett korrekt och säkert sätt.

Ingen föresläsningsserie – aktivt deltagande ger verkliga erfarenheter

Den Java-Dojo som Iptor nu bedrivit har visserligen fått en uppsättning övningar som vi fått efterfrågan på, och därför kunnat upprepa med mycket liknande resultat. Det är dock inget föreläsningspaket som deltagarna kan sova sig igenom – tvärtom skall varje individ sitta i “the hot spot” och parpogrammera. Praktisk erfarenhet och kunskap är mål utöver teoretisk kännedom och bekantskap.

Material

Skall försöka peta ut allt material här. Ikväller blir än så länge bara följande:
JDojo1: TDD och
Kata String Calculator