window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(funktion () { var w = vindue if (w.LeadBooster) { console.warn('LeadBooster findes 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 gør man test lettere? - The Codest
Codest
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Industrier
    • Fintech og bankvirksomhed
    • E-commerce
    • Adtech
    • Sundhedsteknologi
    • Produktion
    • Logistik
    • Biler
    • IOT
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
Pil tilbage GÅ TILBAGE
2022-07-26
Udvikling af software

Testcontainere - Hvordan gør man test lettere?

Bartlomiej Kuczynski

Leder du efter en måde at lave test på en nemmere måde? Så har vi noget til dig! Se den følgende artikel og lær, hvordan du gør det muligt.

Moderne applikationsudvikling er baseret på en enkel regel:

Brug sammensætning

Vi sammensætter klasser, funktioner og tjenester til større stykker software. Det sidste element er grundlaget for mikrotjenester og Sekskantet arkitektur. Vi vil gerne bruge eksisterende løsninger, integrere dem med vores software og gå direkte i gang. marked.

Vil du håndtere kontoregistrering og gemme brugerdata? Du kan vælge en af OAuth-tjenesterne. Måske tilbyder din applikation en form for abonnement eller betaling? Der er mange tjenester, der kan hjælpe dig med at håndtere dette. Har du brug for analyser på dit website, men forstår ikke GDPR? Du er velkommen til at vælge en af de færdige løsninger.

Noget, der gør udvikling så let fra et forretningsmæssigt synspunkt, kan give dig hovedpine - i det øjeblik, hvor du skal skrive en simpel test.

De fantastiske dyr: Køer, databaser og hvordan man tester dem

Unit testing er ret enkelt. Hvis du bare følger reglerne, så vil dit testmiljø og Kode er sunde. Hvilke regler er det?

  • Let at skrive - En enhedstest skal være nem at skrive, fordi man skriver mange af dem. Mindre indsats betyder, at der skrives flere tests.
  • Læsbar - Testkoden skal være let at læse. Testen er en historie. Den beskriver softwarens opførsel og kan bruges som en genvej til dokumentation. En god enhedstest hjælper dig med at rette fejl uden at debugge koden.
  • Pålidelig - Testen bør kun fejle, hvis der er en fejl i det system, der testes. Er det indlysende? Ikke altid. Nogle gange består tests, hvis du kører dem en efter en, men fejler, når du kører dem som et sæt. De består på din maskine, men fejler på CI (Virker på min maskine). En god enhedstest har kun én grund til at fejle.
  • Hurtig - tests skal være hurtige. Forberedelse til kørsel, start og selve testudførelsen skal være meget hurtig. Ellers vil du skrive dem, men ikke køre dem. Langsomme tests betyder mistet fokus. Man venter og kigger på statuslinjen.
  • Uafhængig - Endelig skal testen være uafhængig. Denne regel udspringer af de foregående. Kun virkelig uafhængige tests kan blive til en enhed. De forstyrrer ikke hinanden, kan køres i vilkårlig rækkefølge, og potentielle fejl afhænger ikke af resultaterne af andre tests. Uafhængig betyder også, at man ikke er afhængig af eksterne ressourcer som databaser, beskedtjenester eller filsystem. Hvis du har brug for at kommunikere med eksterne ressourcer, kan du bruge mocks, stubs eller dummies.

Alt bliver kompliceret, når vi vil skrive nogle integrationstests. Det er ikke så slemt, hvis vi gerne vil teste nogle få tjenester sammen. Men når vi skal teste tjenester, der bruger eksterne ressourcer som databaser eller beskedtjenester, så beder vi om problemer.

For at køre testen skal du installere...

For mange år siden, da vi ville lave nogle integrationstest og bruge f.eks. databaser, havde vi to muligheder:

  1. Vi kan installere en database lokalt. Opsæt et skema og opret forbindelse fra vores test;
  2. Vi kan oprette forbindelse til en eksisterende instans "et eller andet sted i rummet".

Begge havde fordele, begge havde ulemper. Men begge introducerer yderligere niveauer af kompleksitet. Nogle gange var det teknisk kompleksitet som følge af visse værktøjers egenskaber, f.eks. installation og styring af Oracle DB på din localhost. Nogle gange var det en ulempe i processen, f.eks. at man skal være enig med testen. hold om JMS-brug ... hver gang du vil køre tests.

Containere til undsætning

I løbet af de sidste 10 år har ideen om containerisering vundet anerkendelse i branchen. Så det er en naturlig beslutning at vælge containere som løsning på vores integrationstestproblem. Det er en enkel og ren løsning. Du kører bare dit proces-build, og så virker det hele! Kan du ikke tro det? Se på denne enkle konfiguration af et maven-build:

.
   
     com.dkanejs.maven.plugins.
     docker-compose-maven-plugin.
     4.0.0
     
       
         up
         test-compile
         
           op
         
         
           ${projekt.basedir}/docker-compose.yml.
           true.
         
       
       
         down
         efter-integrationstest
         
           down
         
         
           ${project.basedir}/docker-compose.yml.
           true.
         
       
     
   
 
.

Og den docker-compose.yml Filen ser også ret flot ud!

version: "3.5"

tjenester:

 postgres:
   container_name: reactivedb
   image: postgres:13.2
   genstart: altid
   miljø:
     - POSTGRES_USER=admin
     - POSTGRES_PASSWORD=password
     - POSTGRES_DB=byer
   porte:
     - "5432:5432"
   mængder:
     - postgres_data:/data/db

 pgadmin:
   container_name: pgadmin4
   image: dpage/pgadmin4
   genstart: altid
   miljø:
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: password
   porte:
     - "15050:80"
   mængder:
     - pgadmin_data:/data/pgadmin

mængder:
 postgres_data:
 pgadmin_data:

Men kan du se problemet her?

Et fragtskib, der blokerer alt

Eksemplet ovenfor er meget enkelt. Bare en postgres-database, pgAdmin og det er alt. Når du kører

bash
$ mvn clean verify

så starter maven-plugin'et containerne og slukker dem efter testene. Problemerne begynder, når projektet vokser, og vores compose-fil også vokser. Hver gang skal du starte alle containere, og de vil være i live gennem hele buildet. Du kan gøre situationen lidt bedre ved at ændre konfigurationen af plugin-udførelsen, men det er ikke nok. I værste fald udnytter dine containere systemets ressourcer, før testene starter!

Og det er ikke det eneste problem. Du kan ikke køre en eneste integrationstest fra dit IDE. Før det skal du starte containerne manuelt. Desuden vil den næste maven-kørsel rive disse containere ned (se på ned udførelse).

Så denne løsning er som et stort fragtskib. Hvis alt fungerer godt, er det ok. Enhver uventet eller usædvanlig adfærd fører os til en form for katastrofe.

Test containere - kør containere fra tests

Men hvad nu, hvis vi kunne køre vores containere fra tests? Ideen ser god ud, og den er allerede ved at blive implementeret. TestcontainereFordi vi taler om dette projekt, er her en løsning på vores problemer. Ikke ideel, men ingen er perfekt.

Dette er en Java biblioteket, som understøtter JUnit- og Spock-tests og giver lette og nemme måder at køre Docker-containeren på. Lad os tage et kig på det og skrive noget kode!

Forudsætninger og konfiguration

Før vi går i gang, skal vi tjekke vores konfiguration. Testbeholdere behov:

  • Docker i version v17.09,
  • Java minimum version 1.8,
  • Adgang til netværk, især til docker.hub.

Du kan læse mere om kravene til specifikke OS og CI her
i dokumentation.

Nu er det tid til at tilføje nogle linjer til pom.xml.

Jeg bruger Spring Boot i projektet for at reducere boilerplate. Testbeholdere er uafhængige af Spring Framework, og du kan bruge dem uden.
org.testcontainers
       testcontainers-bom.
       ${testcontaines.version}
       pom
       import
     
   
 
 
   
     org.postgresql
     postgresql.
     kørselstid.
   
   
     org.testcontainers
     postgresql.
     test
   
   
     org.testcontainers
     junit-jupiter.
     test

Jeg bruger Testbeholdere version 1.17.3men du er velkommen til at bruge den nyeste.

Test med Postgres-container

Det første skridt er at forberede vores instans af en container. Du kan gøre det direkte i testen, men det ser bedre ud med en uafhængig 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() {
   // gør ingenting. Dette er en delt instans. Lad JVM håndtere denne operation.
 }
}

I begyndelsen af testene opretter vi en forekomst af Postgres13TC. Denne klasse kan håndtere oplysninger om vores container. Det vigtigste her er databasens forbindelsesstrenge og legitimationsoplysninger. Nu er det tid til at skrive en meget simpel 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 bruger JUnit 5 her. Annotation @Testcontainere er en del af de udvidelser, der styrer containere i testmiljøet. De finder alle felter med @Container annotation og henholdsvis start- og stopcontainere.

Test med Spring Boot

Som jeg nævnte før, bruger jeg Spring Boot i projektet. I dette tilfælde er vi nødt til at skrive lidt mere kode. Det første skridt er at oprette en ekstra konfigurationsklasse.

@Slf4j
offentlig klasse ContainerInit implementerer
   ApplicationContextInitializer {

 offentlig statisk 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 klasse tilsidesætter de eksisterende egenskaber med værdier fra Testbeholder. De første tre egenskaber er standard Spring-egenskaber. De næste fem er yderligere, brugerdefinerede egenskaber, der kan bruges til at konfigurere andre ressourcer og udvidelser 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

Nu er det tid til at definere en simpel integrationstest.

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

 @Autowired
 privat 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 nogle ekstra kommentarer her.

  • @SpringBootTest(webEnvironment = RANDOM_PORT) - markerer testen som en Spring Boot-test og starter Spring-konteksten.
  • @AutoConfigureTestDatabase(replace = NONE) - Disse annotationer siger, at Spring Test Extension ikke bør erstatte postgres-databasekonfigurationen med H2 i hukommelseskonfigurationen.
  • @ContextConfiguration(initializers = ContainerInit.class) - en ekstra forårskontekst
    konfiguration, hvor vi opsætter egenskaber fra Testbeholdere.
  • @Testcontainere - Som tidligere nævnt styrer denne annotation containerens livscyklus.

I dette eksempel bruger jeg reaktive repositorier, men det fungerer på samme måde med almindelige JDBC- og JPA-repositorier.

Nu kan vi køre denne test. Hvis det er første gang, den køres, skal motoren hente billeder fra docker.hub. Det kan tage et øjeblik. Derefter vil vi se, at to containere har kørt. Den ene er postgres, og den anden er Testcontainers controller. Den anden container styrer de kørende containere, og selv hvis JVM'en uventet stopper, slukker den containerne og rydder op i miljøet.

Lad os opsummere

Testbeholdere er meget brugervenlige værktøjer, som hjælper os med at skabe integrationstest, der bruger Docker-containere. Det giver os mere fleksibilitet og øger udviklingshastigheden. Korrekt opsætning af testkonfiguration reducerer den tid, det tager at sætte nye udviklere i gang. De behøver ikke at opsætte alle afhængigheder, de skal bare køre de skrevne tests med udvalgte konfigurationsfiler.

Samarbejdsbanner

Relaterede artikler

Udvikling af software

Byg fremtidssikrede webapps: Indsigt fra The Codest's ekspertteam

Oplev, hvordan The Codest udmærker sig ved at skabe skalerbare, interaktive webapplikationer med banebrydende teknologier, der leverer sømløse brugeroplevelser på tværs af alle platforme. Lær, hvordan vores ekspertise driver digital transformation og...

DENKODEST
Udvikling af software

Top 10 Letlands-baserede softwareudviklingsvirksomheder

Læs om Letlands bedste softwareudviklingsvirksomheder og deres innovative løsninger i vores seneste artikel. Find ud af, hvordan disse teknologiledere kan hjælpe med at løfte din virksomhed.

thecodest
Løsninger til virksomheder og scaleups

Grundlæggende om Java-softwareudvikling: En guide til succesfuld outsourcing

Udforsk denne vigtige guide til vellykket outsourcing af Java-softwareudvikling for at forbedre effektiviteten, få adgang til ekspertise og skabe projektsucces med The Codest.

thecodest
Udvikling af software

Den ultimative guide til outsourcing i Polen

Den voldsomme stigning i outsourcing i Polen er drevet af økonomiske, uddannelsesmæssige og teknologiske fremskridt, der fremmer it-vækst og et erhvervsvenligt klima.

TheCodest
Løsninger til virksomheder og scaleups

Den komplette guide til IT-revisionsværktøjer og -teknikker

IT-revisioner sikrer sikre, effektive og kompatible systemer. Lær mere om deres betydning ved at læse hele artiklen.

Codest
Jakub Jakubowicz CTO og medstifter

Tilmeld dig vores vidensbase, og hold dig opdateret om ekspertisen fra it-sektoren.

    Om os

    The Codest - International softwareudviklingsvirksomhed med tech-hubs i Polen.

    Storbritannien - Hovedkvarter

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

    Polen - Lokale teknologiske knudepunkter

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

      Codest

    • Hjem
    • Om os
    • Serviceydelser
    • Casestudier
    • Ved hvordan
    • Karriere
    • Ordbog

      Serviceydelser

    • Det rådgivende
    • Udvikling af software
    • Backend-udvikling
    • Frontend-udvikling
    • Staff Augmentation
    • Backend-udviklere
    • Cloud-ingeniører
    • Dataingeniører
    • Andet
    • QA-ingeniører

      Ressourcer

    • Fakta og myter om at samarbejde med en ekstern softwareudviklingspartner
    • Fra USA til Europa: Hvorfor beslutter amerikanske startups sig for at flytte til Europa?
    • Sammenligning af Tech Offshore-udviklingsknudepunkter: Tech Offshore Europa (Polen), ASEAN (Filippinerne), Eurasien (Tyrkiet)
    • Hvad er de største udfordringer for CTO'er og CIO'er?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Vilkår for brug af hjemmesiden

    Copyright © 2025 af The Codest. Alle rettigheder forbeholdes.

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