Etsitkö tapaa tehdä testejä helpommin? Me saimme sinut! Tutustu seuraavaan artikkeliin ja opi, miten se on mahdollista.
Nykyaikainen sovelluskehitys perustuu yhteen yksinkertaiseen sääntöön:
Käytä koostumusta
Kokoonpanemme luokkia, funktioita ja palveluita suuremmiksi ohjelmistokokonaisuuksiksi. Tämä viimeinen elementti on mikropalvelujen ja kuusikulmaisen arkkitehtuurin perusta. Haluaisimme käyttää olemassa olevia ratkaisuja, integroida ne ohjelmistoihimme ja siirtyä suoraan kohti markkinat.
Haluatko käsitellä tilin rekisteröintiä ja tallentaa käyttäjätietoja? Voit valita jonkin OAuth-palveluista. Ehkä sovelluksesi tarjoaa jonkinlaisen tilauksen tai maksun? On monia palveluja, jotka voivat auttaa sinua käsittelemään tämän. Tarvitsetko sivustollesi analytiikkaa, mutta et ymmärrä GDPR:ää? Ota rohkeasti jokin valmiista ratkaisuista.
Jokin, joka tekee kehittämisestä liiketoiminnan kannalta niin helppoa, voi aiheuttaa päänsärkyä - silloin kun sinun on kirjoitettava yksinkertainen testi.
Fantastic Beasts: Jonot, tietokannat ja niiden testaaminen: Jonot, tietokannat ja niiden testaaminen
Yksikkötestaus on melko yksinkertaista. Jos noudatat vain sääntöjä, testausympäristösi ja koodi ovat terveitä. Mitä sääntöjä nuo ovat?
Helppo kirjoittaa - yksikkötestin pitäisi olla helppo kirjoittaa, koska niitä kirjoitetaan paljon. Vähemmän vaivaa tarkoittaa, että testejä kirjoitetaan enemmän.
Luettavissa - testikoodin pitäisi olla helppolukuista. Testi on tarina. Se kuvaa ohjelmiston käyttäytymistä, ja sitä voidaan käyttää dokumentoinnin oikotienä. Hyvä yksikkötesti auttaa korjaamaan virheet ilman koodin virheenkorjausta.
Luotettava - testin pitäisi epäonnistua vain, jos testattavassa järjestelmässä on virhe. Ilmeistä? Ei aina. Joskus testit menevät läpi, jos ne ajetaan yksitellen, mutta epäonnistuvat, kun ne ajetaan kokonaisuutena. Ne menevät läpi omalla koneellasi, mutta epäonnistuvat CI:ssä (Toimii koneessani). Hyvällä yksikkötestillä on vain yksi syy epäonnistumiseen.
Nopea - testien pitäisi olla nopeita. Testien valmistelun, käynnistyksen ja itse testin suorittamisen pitäisi olla erittäin nopeaa. Muuten testit kirjoitetaan, mutta niitä ei ajeta. Hitaat testit merkitsevät keskittymisen menetystä. Odotat ja katsot edistymispalkkia.
Itsenäinen - Lopuksi testin on oltava riippumaton. Tämä sääntö perustuu edellisiin sääntöihin. Vain todella itsenäisistä testeistä voi tulla yksikkö. Ne eivät häiritse toisiaan, ne voidaan suorittaa missä tahansa järjestyksessä, eivätkä mahdolliset virheet riipu muiden testien tuloksista. Riippumattomuus tarkoittaa myös sitä, että testit eivät ole riippuvaisia ulkoisista resursseista, kuten tietokannoista, viestipalveluista tai tiedostojärjestelmästä. Jos sinun on kommunikoitava ulkoisten järjestelmien kanssa, voit käyttää mockeja, stubeja tai dummyja.
Kaikki muuttuu monimutkaiseksi, kun haluamme kirjoittaa integrointitestejä. Se ei ole paha asia, jos haluamme testata muutaman palvelun yhdessä. Mutta kun meidän on testattava palveluita, jotka käyttävät ulkoisia resursseja, kuten tietokantoja tai sanomanvälityspalveluita, joudumme vaikeuksiin.
Testin suorittamiseksi sinun on asennettava...
Kun vuosia sitten halusimme tehdä integrointitestejä ja käyttää esimerkiksi tietokantoja, meillä oli kaksi vaihtoehtoa:
Voimme asentaa tietokannan paikallisesti. Aseta skeema ja muodosta yhteys testistämme;
Voimme muodostaa yhteyden olemassa olevaan instanssiin "jossain avaruudessa".
Molemmilla oli hyvät ja huonot puolensa. Molemmat tuovat kuitenkin lisää monimutkaisuutta. Joskus kyse oli tiettyjen välineiden ominaisuuksista johtuvasta teknisestä monimutkaisuudesta, esimerkiksi Oracle DB:n asentaminen ja hallinta localhostilla. Joskus kyse oli prosessin hankaluudesta, esimerkiksi siitä, että sinun on sovittava testin kanssa. joukkue JMS:n käytöstä... joka kerta, kun haluat suorittaa testejä.
Kontit pelastavat
Viimeisten 10 vuoden aikana konttitoiminnan ajatus on saanut alalla tunnustusta. Luonnollinen päätös on siis valita kontit ratkaisuksi integraatiotestausongelmaamme. Tämä on yksinkertainen ja siisti ratkaisu. Suoritat vain prosessin rakentamisen ja kaikki toimii! Etkö voi uskoa sitä? Katso tätä yksinkertaista maven-buildin konfigurointia:
com.dkanejs.maven.plugins
docker-compose-maven-plugin.
4.0.0
up
test-compile
up
${${.projekti.basedir}/docker-compose.yml
true
down
post-integration-test
down
${project.basedir}/docker-compose.yml
true
Ja docker-compose.yml tiedosto näyttää myös aika hyvältä!
Yllä oleva esimerkki on hyvin yksinkertainen. Vain yksi postgres-tietokanta, pgAdmin ja siinä kaikki. Kun suoritat
bash
$ mvn clean verify
maven-lisäosa käynnistää säiliöt ja sammuttaa ne testien jälkeen. Ongelmat alkavat, kun projekti kasvaa ja myös koostetiedostomme kasvaa. Joka kerta on käynnistettävä kaikki kontit, ja ne ovat elossa koko buildin ajan. Voit parantaa tilannetta hieman muuttamalla pluginin suoritusasetuksia, mutta se ei riitä. Pahimmassa tapauksessa konttiesi kuluttavat järjestelmäresurssit loppuun ennen kuin testit alkavat!
Eikä tämä ole ainoa ongelma. Et voi suorittaa yksittäistä integrointitestiä IDE:stä. Sitä ennen sinun on käynnistettävä kontit käsin. Lisäksi seuraava maven-ajo purkaa nämä kontit (katso esim. alas suorittaminen).
Tämä ratkaisu on siis kuin iso rahtilaiva. Jos kaikki toimii hyvin, niin se on ok. Mikä tahansa odottamaton tai epätavallinen käyttäytyminen johtaa meidät jonkinlaiseen katastrofiin.
Testisäiliöt - aja säiliöitä testeistä
Mutta entä jos voisimme käyttää konttejamme testeistä käsin? Tämä idea näyttää hyvältä, ja sitä toteutetaan jo. Testikontit, koska puhumme tästä hankkeesta, tässä on ratkaisu ongelmiin. Ei ihanteellinen, mutta kukaan ei ole täydellinen.
Tämä on Java kirjasto, joka tukee JUnit- ja Spock-testejä ja tarjoaa kevyitä ja helppoja tapoja ajaa Docker-säiliötä. Tutustutaan siihen ja kirjoitetaan koodia!
Edellytykset ja kokoonpano
Ennen kuin aloitamme, meidän on tarkistettava kokoonpanomme. Testiastiat tarvitsevat:
Docker versiossa v17.09,
Javan vähimmäisversio 1.8,
Pääsy verkkoon, erityisesti docker.hubiin.
Lisätietoja tietyn käyttöjärjestelmän ja CI:n vaatimuksista on saatavilla osoitteessa osoitteessa dokumentaatio.
Nyt on aika lisätä muutamia rivejä kohtaan pom.xml.
org.testcontainers
testcontainers-bom.
${testcontaines.version}
pom
import
org.postgresql
postgresql
runtime
org.testcontainers
postgresql
test
org.testcontainers
junit-jupiter
test
Käytän Testiastiat versio 1.17.3, mutta voit vapaasti käyttää uusinta.
Testit Postgres-säiliön kanssa
Ensimmäinen vaihe on valmistella kontti-instanssimme. Voit tehdä sen suoraan testissä, mutta itsenäinen luokka näyttää paremmalta.
public class Postgres13TC extends PostgreSQLContainer {
private static final Postgres13TC TC = new Postgres13TC();
private Postgres13TC() {
super("postgres:13.2");
}
public static Postgres13TC getInstance() {
return TC;
}
@Override
public void start() {
super.start();
System.setProperty("DB_URL", TC.getJdbcUrl());
System.setProperty("DB_USERNAME", TC.getUsername());
System.setProperty("DB_PASSWORD", TC.getPassword());
}
@Override
public void stop() {
// ei tee mitään. Tämä on jaettu instanssi. Anna JVM:n hoitaa tämä toiminto.
}
}
Testien alussa luomme instanssin luokasta Postgres13TC. Tämä luokka voi käsitellä konttiamme koskevia tietoja. Tärkeimpiä ovat tietokantayhteysmerkkijonot ja tunnistetiedot. Nyt on aika kirjoittaa hyvin yksinkertainen testi.
Käytän tässä JUnit 5:tä. Merkintä @Testikontit on osa laajennuksia, jotka ohjaavat kontteja testiympäristössä. Ne löytävät kaikki kentät, joissa on @Container merkintä ja vastaavasti start- ja stop-säiliöt.
Testit Spring Bootilla
Kuten aiemmin mainitsin, käytän projektissa Spring Bootia. Tässä tapauksessa meidän on kirjoitettava hieman enemmän koodia. Ensimmäinen askel on luoda ylimääräinen konfiguraatioluokka.
Tämä luokka korvaa olemassa olevat ominaisuudet arvoilla luokasta testisäiliö. Kolme ensimmäistä ominaisuutta ovat tavallisia Spring-ominaisuuksia. Seuraavat viisi ovat ylimääräisiä, mukautettuja ominaisuuksia, joita voidaan käyttää muiden resurssien ja laajennusten, kuten liquibasen, konfigurointiin, esim:
Nyt on aika määritellä yksinkertainen integrointitesti.
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@ContextConfiguration(initializers = ContainerInit.class)
@Testikontit
class DummyRepositoryTest {
@Autowired
private DummyRepository;
@Test
void shouldReturnDummy() { void shouldReturnDummy() {
var byId = dummyRepository.getById(10L);
var expected = new Dummy();
expected.setId(10L);
assertThat(byId).completes().emitsCount(1).emits(expected);
}
}
Tässä on joitakin lisämerkintöjä.
@SpringBootTest(webEnvironment = RANDOM_PORT) - merkitsee testin Spring Boot -testiksi ja käynnistää spring-kontekstin.
@AutoConfigureTestDatabase(replace = NONE) - nämä huomautukset sanovat, että spring test -laajennuksen ei pitäisi korvata postgres-tietokannan konfiguraatiota H2:lla muistin konfiguraatiossa.
@ContextConfiguration(initializers = ContainerInit.class) - ylimääräinen kevätkonteksti konfiguraatio, jossa asetamme ominaisuuksia Testiastiat.
@Testikontit - kuten aiemmin mainittiin, tämä merkintä ohjaa säiliön elinkaarta.
Tässä esimerkissä käytän reaktiivisia arkistoja, mutta se toimii samalla tavalla myös tavallisilla JDBC- ja JPA-arkistoilla.
Nyt voimme suorittaa tämän testin. Jos kyseessä on ensimmäinen ajo, moottorin on haettava kuvat docker.hubista. Se voi kestää hetken. Sen jälkeen näemme, että kaksi konttia on ajettu. Toinen on postgres ja toinen on Testcontainers-ohjain. Tuo toinen kontti hallinnoi käynnissä olevia kontteja, ja vaikka JVM pysähtyisi yllättäen, se sammuttaa kontit ja siivoaa ympäristön.
Yhteenveto
Testiastiat ovat erittäin helppokäyttöisiä työkaluja, joiden avulla voimme luoda Docker-astioita käyttäviä integrointitestejä. Tämä antaa meille enemmän joustavuutta ja lisää kehitysnopeutta. Testikokoonpanon oikeaoppinen asettaminen vähentää uusien kehittäjien alustusaikaa. Heidän ei tarvitse määrittää kaikkia riippuvuuksia, vaan ajaa vain kirjoitetut testit valituilla konfiguraatiotiedostoilla.