Java >> Java tutorial >  >> Tag >> Spring

Spock 1.2 – problemfri forårsbønner, der håner i integrationstest

Opdag, hvordan du automatisk injicerer Spocks håner og spioner i forårets kontekst ved hjælp af Spock 1.2.

Stubbe/håner/spioner i Spock (og deres livscyklus) har altid været tæt forbundet med Spock Specification klasse. Det var kun muligt at oprette dem i en testklasse. Derfor var det problematisk at bruge delte, foruddefinerede mocks (i både enheds- og integrationstests).

Situationen blev en smule forbedret i Spock 1.1, men kun med den helt nye Spock 1.2 (1.2-RC1 som skrivende stund) er det lige så nemt at bruge Spock-mocking-undersystemet i Spring-baserede integrationstest som at bruge @SpringMock til Mockito-håner i Spring Boot. Lad os tjekke det op.

Btw, for at være mere banebrydende ud over Spock 1.2-RC1, vil jeg bruge Spring Boot 2.1.0.M2, Spring 5.1.0.RC2 og Groovy 2.5.2 (men alt burde fungere med de stabile versioner af Spring ( Boot) og Groovy 2.4).

En ting mere. For enkelhedens skyld vil jeg i denne artikel bruge et udtryk "hån" til også at henvise til stubbe og spioner. De adskiller sig i adfærd, men med hensyn til at injicere det i Spring-sammenhængen i Spock-testene er det normalt ligegyldigt.

Spock 1.1 – manuel måde

Takket være Leonard Brünings arbejde blev spotter i Spock afkoblet fra Specification klasse. Det var endelig muligt at skabe dem udenfor og senere vedhæfte dem til en løbetest. Det var hjørnestenen i at bruge Spock-håner i foråret (eller enhver anden) sammenhæng.

I denne eksempelkode har vi ShipDatabase klasse, der bruger OwnShipIndex og EnemyShipIndex (selvfølgelig injiceret af en konstruktør :) ) for at returnere aggregeret information om alle kendte skibe matchet efter navn.

//@ContextConfiguration just for simplification, @(Test)Configuration is usually more convenient for Spring Boot tests
//Real beans can exist in the context or not
@ContextConfiguration(classes = [ShipDatabase, TestConfig/*, OwnShipIndex, EnemyShipIndex*/])
class ShipDatabase11ITSpec extends Specification {

    private static final String ENTERPRISE_D = "USS Enterprise (NCC-1701-D)"
    private static final String BORTAS_ENTERA = "IKS Bortas Entera"

    @Autowired
    private OwnShipIndex ownShipIndexMock

    @Autowired
    private EnemyShipIndex enemyShipIndexMock

    @Autowired
    private ShipDatabase shipDatabase

    def "should find ship in both indexes"() {
        given:
            ownShipIndexMock.findByName("Enter") >> [ENTERPRISE_D]
            enemyShipIndexMock.findByName("Enter") >> [BORTAS_ENTERA]
        when:
            List<String> foundShips = shipDatabase.findByName("Enter")
        then:
            foundShips == [ENTERPRISE_D, BORTAS_ENTERA]
    }

    static class TestConfig {
        private DetachedMockFactory detachedMockFactory = new DetachedMockFactory()

        @Bean
        @Primary    //if needed, beware of consequences
        OwnShipIndex ownShipIndexStub() {
            return detachedMockFactory.Stub(OwnShipIndex)
        }

        @Bean
        @Primary    //if needed, beware of consequences
        EnemyShipIndex enemyShipIndexStub() {
            return detachedMockFactory.Stub(EnemyShipIndex)
        }
    }
}

Hånerne er oprettet i en separat klasse (uden for Specification). ) og derfor DetachedMockFactory skal bruges (eller alternativt SpockMockFactoryBean). ). Disse håner skal vedhæftes (og frigøres) til testinstansen (Specification instans), men den håndteres automatisk af spock-spring modul (fra 1.1). For generiske håner oprettet eksternt også MockUtil.attachMock() og mockUtil.detachMock() skal bruges for at få det til at fungere.

Som et resultat var det muligt at skabe og bruge håner i forårssammenhæng, men det var ikke særlig praktisk, og det blev ikke almindeligt brugt.

Spock 1.2 – førsteklasses support

Spring Boot 1.4 bragte den nye kvalitet til integrationstest med (Mockitos) håner. Det udnyttede ideen, der oprindeligt blev præsenteret i Springockito tilbage i 2012 (da Spring-konfigurationen for det meste blev skrevet i XML :) ) til automatisk at injicere håner (eller spioner) i Spring (Boot) konteksten. Spring Boot-teamet udvidede ideen, og takket være at have den som den internt understøttede funktion fungerer den (normalt) pålideligt blot ved at tilføje en annotation eller to i din test.

En lignende annotationsbaseret mekanisme er indbygget i Spock 1.2.

//@ContextConfiguration just for simplification, @(Test)Configuration is usually more convenient for Spring Boot tests
//Real beans can exist in the context or not
@ContextConfiguration(classes = [ShipDatabase/*, OwnShipIndex, EnemyShipIndex*/])
class ShipDatabaseITSpec extends Specification {

    private static final String ENTERPRISE_D = "USS Enterprise (NCC-1701-D)"
    private static final String BORTAS_ENTERA = "IKS Bortas Entera"

    @SpringBean
    private OwnShipIndex ownShipIndexMock = Stub()  //could be Mock() if needed

    @SpringBean
    private EnemyShipIndex enemyShipIndexMock = Stub()

    @Autowired
    private ShipDatabase shipDatabase

    def "should find ship in both indexes"() {
        given:
            ownShipIndexMock.findByName("Enter") >> [ENTERPRISE_D]
            enemyShipIndexMock.findByName("Enter") >> [BORTAS_ENTERA]
        when:
            List<String> foundShips = shipDatabase.findByName("Enter")
        then:
            foundShips == [ENTERPRISE_D, BORTAS_ENTERA]
    }
}

Der er ikke meget at tilføje. @SpringBean instruerer Spock i at injicere en hån i en forårskontekst. Tilsvarende @SpringSpy pakker den rigtige bønne ind med en spion. I tilfælde af @SpringBean det er påkrævet at initialisere et felt for at lade Spock vide, om vi planlægger at bruge en stub eller en mock.

Derudover er der også en mere generel annotation @StubBeans at erstatte alle definerede bønner med stubbe. Jeg planlægger dog at dække det separat i et andet blogindlæg.

Begrænsninger

Til de af jer, der ser frem til at omskrive alle Mockitos håner til Spocks håner i jeres Spock-tests lige efter forelæsningen af ​​denne artikel, er der en advarsel. Spocks håner – på grund af deres natur og relation til Specification – har nogle begrænsninger. Implementeringen under hætten skaber en proxy, som injiceres i Spring-konteksten, som (potentielt) erstatter rigtige bønner (stubbe/håner) eller pakker dem ind (spioner). Denne proxy er delt mellem alle testene i den pågældende test (specifikation) klasse. Faktisk kan den også spænde over andre tests med de samme bean/mock-deklarationer i den situation, hvor Spring er i stand til at cache konteksten (lignende situation som Mockitos mocks eller Spring-integrationstest generelt).

Men hvad der er virkelig vigtigt, er en proxy knyttet til en test lige før dens udførelse og løsrives lige efter den. Derfor har hver test faktisk sin egen mock-instans (den kan ikke anvendes på @Shared felter), og det er problematisk for eksempel at gruppere interaktioner fra forskellige tests og verificere dem sammen (hvilket normalt er ret fornuftigt, men kan føre til en vis duplikering). Ikke desto mindre med at bruge en setup blok (eller in-line stubbing) er det muligt at dele stubbing og interaktionsforventning.

Oversigt

Spock 1.2 bringer endelig problemfri Spocks stubbe/håner/spioner til at bruge dem i Spring-sammenhæng, hvilket er sammenligneligt med det, der leveres i Spring Boot til Mockito. Det er bare nok at tilføje spock-spring modul til projektets (runtime) afhængigheder. På trods af nogle begrænsninger er det et point mindre for at blande indfødte Spocks hånende undersystem med eksterne hånende rammer (såsom Mockito) i dine Spock (integrations) test. Og hvad der er rart, det burde også fungere i almindelige Spring Framework-tests (ikke kun Spring Boot-tests). Den samme funktion er blevet implementeret til Guice (men jeg har ikke testet den).

Ydermere bringer Spock 1.2 også nogle andre ændringer, herunder bedre understøttelse af Java 9+, og det er værd at prøve det i din testpakke (og selvfølgelig rapportere eventuelle potentielt opdagede regressionsfejl :) ).

Endnu en god nyhed. Ud over Leonards arbejde, der gjorde Spock 1.2 muligt og en legion af fejlreportere og PR-bidragydere, er der siden for nylig også nogle andre committers, der arbejder på at gøre Spock endnu bedre. Nogle af dem kender du måske fra nogle andre populære FOSS-projekter. Hvad mere er, Spock 1.2 er (foreløbig) planlagt at være den sidste version baseret på JUnit 4, og den næste stabile Spock-version kunne være 2.0, der udnytter JUnit 5 og (blandt andre) dens oprindelige evne til at køre tests parallelt.

Eksemplerne blev skrevet ved hjælp af Spock 1.2-RC1. Den vil blive opdateret til 1.2-final, når den er udgivet. Kildekoden er tilgængelig fra GitHub.

Java tag