window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versjon: 2, } ;(function () { var w = vindu if (w.LeadBooster) { console.warn('LeadBooster finnes allerede') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Testcontainere - Hvordan gjøre tester enklere? - The Codest
The Codest
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Industrier
    • Fintech og bankvirksomhet
    • E-commerce
    • Adtech
    • Helseteknologi
    • Produksjon
    • Logistikk
    • Bilindustrien
    • IOT
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
Pil tilbake GÅ TILBAKE
2022-07-26
Programvareutvikling

Testcontainere - Hvordan gjøre tester enklere?

Bartlomiej Kuczynski

Leter du etter en måte å gjøre tester på en enklere måte? Da har vi noe for deg! Sjekk følgende artikkel og lær hvordan du kan gjøre det mulig.

Moderne applikasjonsutvikling er basert på én enkel regel:

Bruk sammensetning

Vi setter sammen klasser, funksjoner og tjenester til større deler av programvaren. Det siste elementet er grunnlaget for mikrotjenester og sekskantet arkitektur. Vi ønsker å bruke eksisterende løsninger, integrere dem med programvaren vår og gå rett på marked.

Ønsker du å håndtere kontoregistrering og lagre brukerdata? Du kan velge en av OAuth-tjenestene. Kanskje applikasjonen din tilbyr en form for abonnement eller betaling? Det finnes mange tjenester som kan hjelpe deg med å håndtere dette. Trenger du analyser på nettstedet ditt, men forstår ikke GDPR? Ta gjerne en av de ferdige løsningene.

Noe som gjør utvikling så enkelt fra et forretningsmessig synspunkt, kan gi deg hodepine - når du skal skrive en enkel test.

De fantastiske dyrene: Køer, databaser og hvordan du tester dem

Enhetstesting er ganske enkelt. Hvis du bare følger reglene, vil testmiljøet ditt og kode er sunne. Hvilke regler er det?

  • Lett å skrive - en enhetstest skal være enkel å skrive fordi du skriver mange av dem. Mindre innsats betyr at det skrives flere tester.
  • Lesbar - testkoden skal være lett å lese. Testen er en historie. Den beskriver hvordan programvaren oppfører seg, og kan brukes som en snarvei til dokumentasjon. En god enhetstest hjelper deg med å fikse feil uten å feilsøke koden.
  • Pålitelig - testen skal bare feile hvis det er en feil i systemet som testes. Er det åpenbart? Ikke alltid. Noen ganger består tester hvis du kjører dem én og én, men feiler når du kjører dem som et sett. De består på din maskin, men feiler på CI (Fungerer på min maskin). En god enhetstest har bare én årsak til feil.
  • Rask - testene skal være raske. Forberedelse til kjøring, start og selve testutførelsen bør gå svært raskt. Ellers vil du skrive dem, men ikke kjøre dem. Sakte tester betyr tapt fokus. Du venter og ser på fremdriftslinjen.
  • Uavhengig - Til slutt skal testen være uavhengig. Denne regelen stammer fra de foregående. Bare virkelig uavhengige tester kan bli en enhet. De forstyrrer ikke hverandre, kan kjøres i hvilken som helst rekkefølge, og potensielle feil avhenger ikke av resultatene fra andre tester. Uavhengige betyr også at de ikke er avhengige av eksterne ressurser som databaser, meldingstjenester eller filsystem. Hvis du trenger å kommunisere med eksterne ressurser, kan du bruke mocks, stubber eller dummies.

Alt blir komplisert når vi ønsker å skrive noen integrasjonstester. Det er ikke så ille hvis vi ønsker å teste noen få tjenester sammen. Men når vi skal teste tjenester som bruker eksterne ressurser, som databaser eller meldingstjenester, er vi ute på dypt vann.

For å kjøre testen må du installere...

For mange år siden, da vi ønsket å lage integrasjonstester og bruke f.eks. databaser, hadde vi to alternativer:

  1. Vi kan installere en database lokalt. Sett opp et skjema og koble til fra testen vår;
  2. Vi kan koble oss til en eksisterende instans "et sted i verdensrommet".

Begge hadde fordeler, begge hadde ulemper. Men begge introduserer flere nivåer av kompleksitet. Noen ganger var det teknisk kompleksitet som følge av egenskapene til visse verktøy, f.eks. installasjon og administrasjon av Oracle DB på din lokale host. Noen ganger var det en ulempe i prosessen, f.eks. at du må bli enig med test team om JMS-bruk hver gang du vil kjøre tester.

Containere til unnsetning

I løpet av de siste ti årene har ideen om containerisering blitt anerkjent i bransjen. Derfor var det naturlig å velge containere som løsning på integrasjonstestproblemet vårt. Dette er en enkel og ren løsning. Du kjører bare prosessbyggingen, så fungerer alt! Kan du ikke tro det? Ta en titt på denne enkle konfigurasjonen av en maven-build:

com.dkanejs.maven.plugins
     docker-compose-maven-plugin
     4.0.0
     
       
         up
         test-kompilere
         
           opp
         
         
           ${prosjekt.basedir}/docker-compose.yml.
           true
         
       
       
         down
         post-integrasjonstest
         
           ned
         
         
           ${project.basedir}/docker-compose.yml true
           true

Og docker-compose.yml filen ser også ganske fin ut!

versjon: "3.5"

tjenester:

 postgres:
   container_name: reactivedb
   image: postgres:13.2
   restart: alltid
   environment:
     - POSTGRES_USER=admin
     - POSTGRES_PASSWORD=passord
     - POSTGRES_DB=byer
   ports:
     - "5432:5432"
   volumes:
     - postgres_data:/data/db

 pgadmin:
   container_name: pgadmin4
   image: dpage/pgadmin4
   restart: alltid
   environment:
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: password
   ports:
     - "15050:80"
   volumer
     - pgadmin_data:/data/pgadmin

volumes:
 postgres_data:
 pgadmin_data:

Men kan du se problemet her?

Et lasteskip som blokkerer alt

Eksemplet ovenfor er veldig enkelt. Bare én postgres-database, pgAdmin og det er alt. Når du kjører

bash
$ mvn clean verify

så starter maven-plugin-modulen containerne og slår dem av etter testene. Problemene oppstår når prosjektet vokser, og Compose-filen vår også vokser. Hver gang må du starte alle containerne, og de vil være i live gjennom hele byggingen. Du kan gjøre situasjonen litt bedre ved å endre konfigurasjonen for kjøring av plugin-modulen, men det er ikke nok. I verste fall bruker containerne opp systemressursene dine før testene starter!

Og dette er ikke det eneste problemet. Du kan ikke kjøre en eneste integrasjonstest fra IDE-en din. Før det må du starte containerne for hånd. Dessuten vil neste maven-kjøring rive ned disse containerne (ta en titt på ned utførelse).

Så denne løsningen er som et stort lasteskip. Hvis alt fungerer bra, er alt i orden. Enhver uventet eller uvanlig oppførsel fører oss til en slags katastrofe.

Testcontainere - kjør containere fra tester

Men hva om vi kunne kjøre containerne våre fra tester? Denne ideen ser god ut, og den er allerede i ferd med å bli implementert. TestcontainereSiden vi snakker om dette prosjektet, her er en løsning på problemene våre. Ikke ideelt, men ingen er perfekt.

Dette er en Java biblioteket, som støtter JUnit- og Spock-tester, og som gir lette og enkle måter å kjøre Docker-containeren på. La oss ta en titt på det og skrive litt kode!

Forutsetninger og konfigurasjon

Før vi begynner, må vi sjekke konfigurasjonen vår. Testbeholdere behov:

  • Docker i versjon v17.09,
  • Java minimum versjon 1.8,
  • Tilgang til nettverk, spesielt til docker.hub.

Mer om kravene til spesifikke operativsystemer og CI finner du her
i dokumentasjon.

Nå er det på tide å legge til noen linjer til pom.xml.

Jeg bruker Spring Boot i prosjektet for å redusere boilerplate. Testbeholdere er uavhengige av Spring Framework, og du kan bruke dem uten det.
org.testcontainers
       testcontainers-bom $
       ${testcontainers.versjon}
       pom
       import
     
   
  
 
   
     org.postgresql
     postgresql runtime</s/s
     runtime
   
   
     org.testcontainers
     postgresql test
     test
   
   
     org.testcontainers
     junit-jupiter test</scope
     test

Jeg bruker Testbeholdere versjon 1.17.3men bruk gjerne den nyeste.

Tester med Postgres-container

Det første trinnet er å klargjøre en containerforekomst. Du kan gjøre det direkte i testen, men det ser bedre ut med en uavhengig klasse.

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() {
   // gjør ingenting. Dette er en delt instans. La JVM håndtere denne operasjonen.
 }
}

I begynnelsen av testene oppretter vi en forekomst av Postgres13TC. Denne klassen kan håndtere informasjon om containeren vår. Det viktigste her er databasens tilkoblingsstrenger og legitimasjon. Nå er det på tide å skrive en veldig enkel test.

@Testcontainere
class SimpleDbTest {

 @Container
 private static Postgres13TC = Postgres13TC.getInstance();

 @Test
 void testConnection() {
   assumeThat(postgres13TC.isRunning());
   var connectionProps = new Properties();
   connectionProps.put("user", postgres13TC.getUsername());
   connectionProps.put("password", postgres13TC.getPassword());

   try (Connection = DriverManager.getConnection(postgres13TC.getJdbcUrl(),
       connectionProps)) {
     var resultSet = connection.prepareStatement("Select 1").executeQuery();
     resultSet.next();
     assertThat(resultSet.getInt(1)).isEqualTo(1);
   } catch (SQLException sqlException) {
     assertThat((Exception) sqlException).doesNotThrowAnyException();
   }
 }
}

Jeg bruker JUnit 5 her. Annotasjon @Testcontainere er en del av utvidelsene som kontrollerer containere i testmiljøet. De finner alle felt med @Container annotasjon og henholdsvis start- og stoppcontainere.

Tester med Spring Boot

Som jeg nevnte tidligere, bruker jeg Spring Boot i prosjektet. I dette tilfellet må vi skrive litt mer kode. Det første trinnet er å opprette en ekstra konfigurasjonsklasse.

@Slf4j
public class ContainerInit implementerer
   ApplicationContextInitializer {

 public static Postgres13TC;

 static {
   postgres13TC = Postgres13TC.getInstance();
   postgres13TC.start();
 }

 @Override
 public void initialize(ConfigurableApplicationContext applicationContext) {
   TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
       applicationContext,
       "spring.datasource.url=" + postgres13TC.getJdbcUrl(),
       "spring.datasource.username=" + postgres13TC.getUsername(),
       "spring.datasource.password=" + postgres13TC.getPassword(),
       "db.host=" + postgres13TC.getHost(),
       "db.port=" + postgres13TC.getMappedPort(postgres13TC.POSTGRESQL_PORT),
       "db.name=" + postgres13TC.getDatabaseName(),
       "db.username=" + postgres13TC.getUsername(),
       "db.password=" + postgres13TC.getPassword()
   );
 }
}

Denne klassen overstyrer de eksisterende egenskapene med verdier fra testbeholder. De tre første egenskapene er standard Spring-egenskaper. De neste fem er ekstra, tilpassede egenskaper som kan brukes til å konfigurere andre ressurser og utvidelser som f.eks. liquibase:

spring.liquibase.change-log=classpath:/db/changelog/dbchangelog.xml
spring.liquibase.url=jdbc:postgresql://${db.host:localhost}:${db.port:5432}/${db.name:cities}
spring.liquibase.user=${db.username:admin}
spring.liquibase.password=${db.password:password}
spring.liquibase.enabled=true

Nå er det på tide å definere en enkel integrasjonstest.

@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@ContextConfiguration(initialisatorer = ContainerInit.class)
@Testcontainere
class DummyRepositoryTest {

 @Autowired
 private DummyRepository;

 @Test
 void shouldReturnDummy() {
   var byId = dummyRepository.getById(10L);
   var expected = new Dummy();
   expected.setId(10L);
   assertThat(byId).completes().emitsCount(1).emits(expected);
 }
}

Vi har noen ekstra kommentarer her.

  • @SpringBootTest(webEnvironment = RANDOM_PORT) - markerer testen som en Spring Boot-test og starter Spring-konteksten.
  • @AutoConfigureTestDatabase(replace = NONE) - disse merknadene sier at vårens testutvidelse ikke skal erstatte postgres-databasekonfigurasjonen med H2 i minnekonfigurasjonen.
  • @ContextConfiguration(initialisatorer = ContainerInit.class) - en ekstra vårkontekst
    konfigurasjon der vi setter opp egenskaper fra Testbeholdere.
  • @Testcontainere - som tidligere nevnt, kontrollerer denne annotasjonen beholderens livssyklus.

I dette eksempelet bruker jeg reaktive repositorier, men det fungerer på samme måte med vanlige JDBC- og JPA-repositorier.

Nå kan vi kjøre denne testen. Hvis det er første gang, må motoren hente bilder fra docker.hub. Det kan ta et øyeblikk. Etter det vil vi se at to containere har kjørt. Den ene er postgres og den andre er Testcontainers-kontrolleren. Den andre containeren administrerer containere som kjører, og selv om JVM uventet stopper, slår den av containerne og rydder opp i miljøet.

La oss oppsummere

Testbeholdere er svært brukervennlige verktøy som hjelper oss med å lage integrasjonstester som bruker Docker-containere. Det gir oss mer fleksibilitet og øker utviklingshastigheten. Riktig oppsett av testkonfigurasjon reduserer tiden det tar for nye utviklere å gå om bord. De trenger ikke å sette opp alle avhengigheter, men kan bare kjøre de skrevne testene med utvalgte konfigurasjonsfiler.

samarbeidsbanner

Relaterte artikler

Programvareutvikling

Bygg fremtidssikre webapper: Innsikt fra The Codests ekspertteam

Oppdag hvordan The Codest utmerker seg når det gjelder å skape skalerbare, interaktive webapplikasjoner med banebrytende teknologi som gir sømløse brukeropplevelser på tvers av alle plattformer. Finn ut hvordan ekspertisen vår driver digital transformasjon og...

THECODEST
Programvareutvikling

Topp 10 Latvia-baserte programvareutviklingsselskaper

I vår nyeste artikkel kan du lese mer om Latvias beste programvareutviklingsselskaper og deres innovative løsninger. Oppdag hvordan disse teknologilederne kan bidra til å løfte virksomheten din.

thecodest
Løsninger for bedrifter og oppskalering

Grunnleggende om Java-programvareutvikling: En guide til vellykket outsourcing

Utforsk denne viktige veiledningen om vellykket outsourcing av Java-programvareutvikling for å øke effektiviteten, få tilgang til ekspertise og drive frem prosjektsuksess med The Codest.

thecodest
Programvareutvikling

Den ultimate guiden til outsourcing i Polen

Den kraftige økningen i outsourcing i Polen er drevet av økonomiske, utdanningsmessige og teknologiske fremskritt, noe som fremmer IT-vekst og et forretningsvennlig klima.

TheCodest
Løsninger for bedrifter og oppskalering

Den komplette guiden til verktøy og teknikker for IT-revisjon

IT-revisjoner sørger for sikre, effektive og kompatible systemer. Les hele artikkelen for å lære mer om viktigheten av dem.

The Codest
Jakub Jakubowicz CTO og medgrunnlegger

Abonner på vår kunnskapsbase og hold deg oppdatert på ekspertisen fra IT-sektoren.

    Om oss

    The Codest - Internasjonalt programvareutviklingsselskap med teknologisentre i Polen.

    Storbritannia - Hovedkvarter

    • Kontor 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokale teknologisentre

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polen

      The Codest

    • Hjem
    • Om oss
    • Tjenester
    • Casestudier
    • Vet hvordan
    • Karriere
    • Ordbok

      Tjenester

    • Det rådgivende
    • Programvareutvikling
    • Backend-utvikling
    • Frontend-utvikling
    • Staff Augmentation
    • Backend-utviklere
    • Ingeniører i skyen
    • Dataingeniører
    • Annet
    • QA-ingeniører

      Ressurser

    • Fakta og myter om samarbeid med en ekstern programvareutviklingspartner
    • Fra USA til Europa: Hvorfor velger amerikanske oppstartsbedrifter å flytte til Europa?
    • Sammenligning av Tech Offshore Development Hubs: Tech Offshore Europa (Polen), ASEAN (Filippinene), Eurasia (Tyrkia)
    • Hva er de største utfordringene for CTO-er og CIO-er?
    • The Codest
    • The Codest
    • The Codest
    • Retningslinjer for personver
    • Vilkår for bruk av nettstedet

    Opphavsrett © 2025 av The Codest. Alle rettigheter forbeholdt.

    nb_NONorwegian
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek nb_NONorwegian