Kontinuerlig test med mikrotjenester (med eksempler)


Hvornår er Microservice Architecture vejen frem?

Det er afgørende at vælge og designe den korrekte arkitektur til et system. Man skal sikre kvaliteten af servicekravene og håndteringen af ikke-funktionelle krav, såsom vedligeholdelse, udvidelsesmuligheder og testbarhed.

Mikroservicearkitektur er et ganske tilbagevendende valg i de nyeste økosystemer, efter at virksomheder har vedtaget Agile og DevOps. Selvom det ikke er et de facto-valg, er det en af de foretrukne muligheder, når det drejer sig om systemer, der vokser meget, og hvor en monolitarkitektur ikke længere er mulig at vedligeholde. Ved at holde komponenter serviceorienterede og løst koblede tillader det løbende udvikling og frigivelsescyklusser. Dette får virksomheder til konstant at teste og opgradere deres software.

De vigtigste forudsætninger, der kræver en sådan arkitektur, er:

  • Domænedrevet design
  • Kontinuerlig levering og DevOps-kultur
  • Isolering af fejl
  • Decentralisering

Det har følgende fordele:

  • Holdejerskab
  • Hyppige udgivelser
  • Lettere vedligeholdelse
  • Nemmere opgraderinger til nyere versioner
  • Teknologiagnostiker

Det har følgende ulemper:

  • mikroservice-til-mikroservice kommunikationsmekanismer
  • At øge antallet af tjenester øger den samlede systemkompleksitet

Jo mere distribueret og kompleks arkitekturen er, jo mere udfordrende er det at sikre, at systemet kan udvides og vedligeholdes, samtidig med at omkostninger og risici kontrolleres. En forretningstransaktion kan involvere flere kombinationer af protokoller og teknologier. Det handler ikke kun om use cases, men også om dets drift. Når man anvender Agile og DevOps tilgange, bør man finde en balance mellem fleksibilitet versus funktionalitet med det formål at opnå kontinuerlig revision og test.

Vigtigheden af teststrategier i relation til mikrotjenester

Vedtagelse af DevOps i en organisation har til formål at eliminere de forskellige isolerede afdelinger og bevæge sig mod ét samlet team. Dette træk søger specifikt at forbedre relationerne og processerne mellem softwareteamet og driftsteamet. At levere i et hurtigere tempo betyder også at sikre, at der er løbende test som en del af softwareleveringspipelinen. Udrulning dagligt (og i nogle tilfælde endda hver par timer) er et af hovedmålene for hurtig levering af end-to-end forretningsløsninger. Pålidelighed og sikkerhed skal huskes her, og det er her test kommer ind.

Inkluderingen af testdrevet udvikling er den eneste måde at opnå ægte tillid til, at kode er produktionsklar. Gyldige testcases tilføjer værdi til systemet, da de validerer og dokumenterer selve systemet. Bortset fra det tilskynder god kodedækning til forbedringer og hjælper under refactoring.

Microservices arkitektur decentraliserer kommunikationskanaler, hvilket gør testning mere kompliceret. Det er ikke et uoverkommeligt problem. Et team, der ejer en mikroservice, bør ikke være bange for at indføre ændringer, fordi de kan ødelægge eksisterende klientapplikationer. Manuel test er meget ineffektivt i betragtning af, at kontinuerlig integration og kontinuerlig implementering er den nuværende bedste praksis. DevOps-ingeniører bør sørge for at inkludere automatiseringstests i deres udviklingsworkflow: skrive test, tilføje/refaktor kode og køre test.

Almindelige mikroservice-testmetoder

Testpyramiden er et nemt koncept, der hjælper os med at identificere den indsats, der kræves, når man skriver test, og hvor antallet af tests skal falde, hvis granulariteten falder. Det gælder også, når man overvejer løbende test af mikrotjenester.

For at gøre emnet mere konkret vil vi tage fat på testen af en prøvemikrotjeneste ved hjælp af Spring Boot og Java. Mikroservicearkitekturer er efter konstruktion mere komplicerede end monolitisk arkitektur. Ikke desto mindre vil vi holde fokus på typen af test og ikke på arkitekturen. Vores uddrag er baseret på et minimalt projekt bestående af én API-drevet mikrotjeneste, der ejer et datalager ved hjælp af MongoDB.

Enhedstest

Enhedstest bør være størstedelen af testene, da de er hurtige, pålidelige og nemme at vedligeholde. Disse tests kaldes også white-box tests. Ingeniøren, der implementerer dem, er fortrolig med logikken og skriver testen for at validere modulspecifikationerne og kontrollere kvaliteten af koden.

Fokus for disse tests er en lille del af systemet isoleret set, dvs. Class Under Test (CUT). The Single Responsibility Principle er en god guideline til, hvordan man administrerer kode i forbindelse med funktionalitet.

Den mest almindelige form for en enhedstest er en "ensom enhedstest. ” Det krydser ingen grænser og har ikke brug for nogen samarbejdspartnere bortset fra CUT.

Som skitseret af Bill Caputo, er databaser, meddelelseskanaler eller andre systemer grænserne; enhver yderligere klasse, der bruges eller kræves af CUT, er en samarbejdspartner. En enhedstest bør aldrig krydse en grænse. Når man gør brug af samarbejdspartnere, skriver man en "social unit tests. ” At bruge mocks til afhængigheder, der bruges af CUT, er en måde at teste omgængelig kode på med en “ensom enhedstest. ”

I traditionelle softwareudviklingsmodeller var udviklertest endnu ikke vildt taget i brug, da de skulle teste fuldstændig off-sync fra udvikling. At opnå en høj kodedækningsvurdering blev betragtet som en nøgleindikator for testsuites tillid.

Med introduktionen af Agile og korte iterative cyklusser er det tydeligt nu, at tidligere testmodeller ikke længere virker. Hyppige ændringer forventes løbende. Det er meget mere kritisk at teste observerbar adfærd i stedet for at få dækket alle kodestier. Enhedstest bør handle mere om påstande end kodedækning, fordi målet er at bekræfte, at logikken fungerer som forventet.

Det er nytteløst at have en komponent med masser af test og en høj procentdel af kodedækning, når testene ikke har ordentlige påstande. Anvendelse af en mere adfærdsdrevet udvikling (BDD) tilgang sikrer, at tests verificerer sluttilstanden, og at adfærden matcher de krav, som virksomheden stiller. Fordelen ved at have fokuserede test med et veldefineret omfang er, at det bliver lettere at identificere årsagen til fejlen. BDD-test giver os større tillid til, at fejl var en konsekvens af en ændring i funktionsadfærd. Tests, der ellers fokuserer mere på kodedækning, kan ikke give meget tillid, da der ville være en højere risiko for, at fejl er en konsekvens for ændringer, der er foretaget i selve testene på grund af kodesti-implementeringsdetaljer.

Tests bør følge Martin Fowlers forslag, da han udtalte følgende (i Refactoring: Improving the Design of Existing Code, Second Edition. Kent Beck og Martin Fowler. Addison-Wesley. 2018):

En anden grund til at fokusere mindre på mindre implementeringsdetaljer er refaktorering. Under refactoring bør enhedstests være der for at give os selvtillid og ikke bremse arbejdet. En ændring i implementeringen af samarbejdspartneren kan resultere i en testfejl, hvilket kan gøre testene sværere at vedligeholde. Det anbefales stærkt at holde et minimum af omgængelige enhedstests. Dette er især tilfældet, når sådanne test kan bremse udviklingens livscyklus med mulighed for, at test ender med at blive ignoreret. En fremragende situation at inkludere en social enhedstest er negativ test, især når det drejer sig om adfærdsverifikation.

Integrationstest

En af de væsentligste udfordringer med mikrotjenester er at teste deres interaktion med resten af infrastrukturtjenesterne, det vil sige de grænser, som den særlige CUT afhænger af, såsom databaser eller andre tjenester. Testpyramiden viser tydeligt, at integrationstests bør være mindre end enhedstests, men mere end komponent- og ende-til-ende-tests. Disse andre typer test kan være langsommere, sværere at skrive og vedligeholde og være ret skrøbelige sammenlignet med enhedstests. Overskridelse af grænser kan have en indvirkning på ydeevne og eksekveringstid på grund af netværks- og databaseadgang; stadig er de uundværlige, især i DevOps-kulturen.

I et kontinuerligt implementeringsområde foretrækkes smalle integrationstests i stedet for brede integrationstests. Sidstnævnte er meget tæt på end-to-end-tests, hvor det kræver, at den faktiske service kører i stedet for brugen af en testdobbelt af disse tjenester for at teste kode-interaktionerne. Hovedmålet at opnå er at bygge håndterbare operative tests på en hurtig, nem og modstandsdygtig måde. Integrationstests fokuserer på interaktionen af CUT til én tjeneste ad gangen. Vores fokus er på smalle integrationstests. Verifikation af interaktionen mellem et par tjenester kan bekræftes som forventet, hvor tjenester enten kan være en infrastrukturtjeneste eller en hvilken som helst anden tjeneste.

Persistenstest

>

En kontroversiel type test er, når man tester persistenslaget, med det primære formål at teste forespørgslerne og effekten på testdata. En mulighed er brugen af in-memory databaser. Nogle vil måske overveje brugen af in-memory-databaser som en social enhedstest, da det er en selvstændig test, idempotent og hurtig. Testen kører mod den database, der er oprettet med den ønskede konfiguration. Efter at testkørslerne og påstande er verificeret, skrubbes datalageret automatisk, når JVM'en afsluttes på grund af dens flygtige natur. Husk, at der stadig sker en forbindelse til en anden tjeneste og betragtes som en snæver integrationstest. I en testdrevet udviklingstilgang (TDD) er sådanne tests essentielle, da testpakker bør køre inden for få sekunder. In-memory-databaser er en gyldig afvejning for at sikre, at testene holdes så hurtigt som muligt og ikke ignoreres i det lange løb.

@Before
public void setup() throws Exception {
   try {
	// this will download the version of mongo marked as production. One should
	// always mention the version that is currently being used by the SUT
	String ip = "localhost";
	int port = 27017;

	IMongodConfig mongodConfig = new MongodConfigBuilder().version(Version.Main. PRODUCTION)
		.net(new Net(ip, port, Network.localhostIsIPv6())).build();

	MongodStarter starter = MongodStarter.getDefaultInstance();
mongodExecutable = starter.prepare(mongodConfig);
	mongodExecutable.start();

   } catch (IOException e) {
	e.printStackTrace();
   }
}

Snippet 1: Installation og opstart af In-memory MongoDB

Ovenstående er ikke en komplet integrationstest, da en database i hukommelsen ikke opfører sig nøjagtigt som produktionsdatabaseserveren. Derfor er det ikke en replika til den "rigtige" mongo-server, hvilket ville være tilfældet, hvis man vælger brede integrationstests.

En anden mulighed for persistensintegrationstest er at have brede test kørende forbundet til en egentlig databaseserver eller med brug af containere. Containere letter smerten, da man efter anmodning leverer databasen, sammenlignet med at have en fast server. Husk, at sådanne test er tidskrævende, og at kategorisere test er en mulig løsning. Da disse test afhænger af en anden tjeneste, der kører bortset fra CUT, betragtes det som en systemtest. Disse tests er stadig essentielle, og ved at bruge kategorier kan man bedre afgøre, hvornår specifikke test skal køre for at få den bedste balance mellem omkostninger og værdi. For eksempel kan man under udviklingscyklussen kun køre de smalle integrationstests ved hjælp af in-memory-databasen. Natlige builds kunne også køre test, der falder ind under en kategori såsom brede integrationstests.

@Category(FastIntegration.class)
@RunWith(SpringRunner.class)
@DataMongoTest
public class DailyTaskRepositoryInMemoryIntegrationTest {
	. . . 
}

@Category(SlowIntegration.class)
@RunWith(SpringRunner.class)
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class DailyTaskRepositoryIntegrationTest {
   ...
}

Snippet 2: Brug af kategorier til at differentiere typerne af integrationstests

Forbrugerdrevne tests

Inter-Process Communication (IPC) mekanismer er et centralt aspekt af distribuerede systemer baseret på en mikroservicearkitektur. Denne opsætning rejser forskellige komplikationer under oprettelsen af testsuiter. Derudover er ændringer i et Agile-team løbende i gang, herunder ændringer i API'er eller begivenheder. Uanset hvilken IPC-mekanisme systemet bruger, er der tilstedeværelsen af en kontrakt mellem to tjenester. Der findes forskellige typer kontrakter, alt efter hvilken mekanisme man vælger at bruge i systemet. Ved brug af API'er er kontrakten HTTP-anmodningen og -svaret, mens kontrakten i tilfælde af et hændelsesbaseret system er selve domænehændelsen.

Et primært mål ved test af mikrotjenester er at sikre, at disse kontrakter er veldefinerede og stabile på ethvert tidspunkt. I en TDD top-down tilgang er disse de første tests, der skal dækkes. En grundlæggende integrationstest sikrer, at forbrugeren får hurtig feedback, så snart en kunde ikke matcher den reelle tilstand hos den producent, som den taler til.

Disse test bør være en del af den almindelige implementeringspipeline. Deres fejl ville gøre det muligt for forbrugerne at blive opmærksomme på, at der er sket en ændring på producentsiden, og at der er behov for ændringer for at opnå konsistens igen. Uden behovet for at skrive indviklede ende-til-ende-tests, ville 'forbrugerdrevet kontrakttest' målrette denne brugssag.

Det følgende er et eksempel på en kontraktverifikator, der er genereret af spring-cloud-contract plugin.

@Test
public void validate_add_New_Task() throws Exception {
  // given:
   MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json;charset=UTF-8")
	.body("{"taskName":"newTask","taskDescription":"newDescription","isComplete":false,"isUrgent":true}");

  // when:
   ResponseOptions response = given().spec(request).post("/tasks");

  // then:
   assertThat(response.statusCode()).isEqualTo(200);
   assertThat(response.header("Content-Type")).isEqualTo("application/json;charset=UTF-8");
  // and:
   DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
   assertThatJson(parsedJson).field("['taskName']").isEqualTo("newTask");
   assertThatJson(parsedJson).field("['isUrgent']").isEqualTo(true);
   assertThatJson(parsedJson).field("['isComplete']").isEqualTo(false);
   assertThatJson(parsedJson).field("['id']").isEqualTo("3");
   assertThatJson(parsedJson).field("['taskDescription']").isEqualTo("newDescription");
}

Snippet 3: Contract Verifier, der er automatisk genereret af spring-cloud-contract-pluginnet

En BaseClass skrevet i producenten instruerer, hvilken slags svar man kan forvente på de forskellige typer anmodninger ved at bruge den selvstændige opsætning. Den pakkede samling af stubber er tilgængelig for alle forbrugere for at kunne trække dem i deres implementering. Kompleksiteten opstår, når flere forbrugere gør brug af den samme kontrakt; derfor skal producenten have et globalt overblik over de servicekontrakter, der kræves.

@RunWith(SpringRunner.class)
@SpringBootTest
public class ContractBaseClass {

	@Autowired
	private DailyTaskController taskController;

	@MockBean
	private DailyTaskRepository dailyTaskRepository;

	@Before
	public void before() {
		RestAssuredMockMvc.standaloneSetup(this.taskController);
		Mockito.when(this.dailyTaskRepository.findById("1")).thenReturn(
Optional.of(new DailyTask("1", "Test", "Description", false, null)));
		
		. . . 
				
		Mockito.when(this.dailyTaskRepository.save(
new DailyTask(null, "newTask", "newDescription", false, true))).thenReturn(
new DailyTask("3", "newTask", "newDescription", false, true));
		
	}

Snippet 4: Producentens BaseClass definerer det forventede svar for hver anmodning

På forbrugersiden, med inklusion af spring-cloud-starter-contract-stub-runner-afhængigheden, konfigurerede vi testen til at bruge stubs binær. Denne test ville køre ved hjælp af stubs genereret af producenten i henhold til konfigurationen, hvis version er angivet eller altid den seneste. Stub-artefakten forbinder klienten med producenten for at sikre, at begge arbejder på samme kontrakt. Enhver ændring, der opstår, vil afspejle sig i disse test, og forbrugeren vil således identificere, om producenten har ændret sig eller ej.

@SpringBootTest(classes = TodayAskApplication.class)
@RunWith(SpringRunner.class)
@AutoConfigureStubRunner(ids = "com.cwie.arch:today:+:stubs:8080", stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class TodayClientStubTest {
 	 . . .
	@Test
	public void addTask_expectNewTaskResponse () {
		Task newTask = todayClient.createTask(
new Task(null, "newTask", "newDescription", false, true));
		BDDAssertions.then(newTask).isNotNull();
		BDDAssertions.then(newTask.getId()).isEqualTo("3");
		. . . 
		
	}
}

Snippet 5: Forbruger injicerer stubversionen defineret af producenten

Sådanne integrationstests bekræfter, at en udbyders API stadig er i overensstemmelse med forbrugernes forventninger. Når vi brugte hånede enhedstests til API'er, ville vi have stoppet API'er og hånet adfærden. Fra et forbrugersynspunkt vil disse typer test sikre, at kunden lever op til vores forventninger. Det er vigtigt at bemærke, at hvis producentsiden ændrer API'et, vil disse test ikke mislykkes. Og det er bydende nødvendigt at definere, hvad testen dækker over.

// the response we expect is represented in the task1.json file
private Resource taskOne = new ClassPathResource("task1.json");

@Autowired
private TodayClient todayClient;

@Test
public void createNewTask_expectTaskIsCreated() {
WireMock.stubFor(WireMock.post(WireMock.urlMatching("/tasks"))
		.willReturn(WireMock.aResponse()
		.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
		.withStatus(HttpStatus.OK.value())
		.withBody(transformResourceJsonToString(taskOne))));
		
	Task tasks = todayClient.createTask(new Task(null, "runUTest", "Run Test", false, true));
	BDDAssertions.then(tasks.getId()).isEqualTo("1");

Snippet 6: En forbrugertest med påstande om sit eget definerede svar

Komponenttests

Mikroservicearkitektur kan vokse hurtigt, og derfor kan den komponent, der testes, integreres med flere andre komponenter og flere infrastrukturtjenester. Indtil nu har vi dækket white-box-test med enhedstests og smalle integrationstests for at teste CUT'en, der krydser grænsen for at integrere med en anden tjeneste.

Den hurtigste form for komponenttestning er in-proces-tilgangen, hvor testning ud over brugen af testdobler og in-memory datalagre forbliver inden for grænserne. Den største ulempe ved denne tilgang er, at den deployerbare produktionstjeneste ikke er fuldt testet; tværtimod kræver komponenten ændringer for at koble applikationen anderledes. Den foretrukne metode er test af komponenter uden for processen. Disse er som ende-til-ende-tests, men med alle eksterne samarbejdspartnere skiftet ud med testdobler, udøver den ved at gøre det den fuldt implementerede artefakt ved at bruge rigtige netværksopkald. Testen vil være ansvarlig for korrekt konfiguration af eksterne tjenester som stubs.

@Ignore
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { TodayConfiguration.class, TodayIntegrationApplication.class,
   CloudFoundryClientConfiguration.class })
public class BaseFunctionalitySteps {

   @Autowired
   private CloudFoundryOperations cf;

   private static File manifest = new File(".manifest.yml");

   @Autowired
   private TodayClient client;

   // Any stubs required 
   . . . 

   public void setup() {

cf.applications().pushManifest(PushApplicationManifestRequest.builder() 
 
 .manifest(ApplicationManifestUtils.read(manifest.toPath()).get(0)).build()).block();
}
. . .
// Any calls required by tests
public void requestForAllTasks() {
this.client.getTodoTasks();
}
}

Snippet 7: Implementering af manifestet på CloudFoundry og eventuelle opkald, der kræves af test

Cloud Foundry er en af mulighederne, der bruges til containerbaserede testarkitekturer. "Det er en open source cloud-applikationsplatform, der gør det hurtigere og nemmere at bygge, teste, implementere og skalere applikationer. ” Følgende er manifest.yml, en fil, der definerer konfigurationen af alle applikationer i systemet. Denne fil bruges til at implementere den faktiske tjeneste i det produktionsklare format på Pivotal-organisationens plads, hvor MongoDB-tjenesten allerede er konfigureret, og matcher produktionsversionen.

---
applications:
- name: today
  instances: 1
  path: ../today/target/today-0.0.1-SNAPSHOT.jar 
  memory: 1024M
  routes:
  - route: today.cfapps.io
  services:
  - mongo-it

Snippet 8: Implementering af én forekomst af tjenesten afhængigt af mongo-tjenesten

Når du vælger out-of-proces-tilgangen, skal du huske på, at faktiske grænser er under test, og derfor ender tests med at blive langsommere, da der er netværks- og databaseinteraktioner. Det ville være ideelt at få disse testpakker skrevet i et separat modul. For at kunne køre dem separat på et andet maven-stadium i stedet for den sædvanlige 'test'-fase.

Da vægten af testene ligger på selve komponenten, dækker testene komponentens primære ansvar, mens man målrettet negligerer enhver anden del af systemet.

Cucumber, et softwareværktøj, der understøtter adfærdsdrevet udvikling, er en mulighed for at definere sådanne adfærdstests. Med sin almindelige sprogparser, Gherkin, sikrer den, at kunder nemt kan forstå alle beskrevne test. Følgende Cucumber-funktionsfil sikrer, at vores komponentimplementering matcher forretningskravene for den pågældende funktion.

Feature: Tasks

Scenario: Retrieving one task from list
 Given the component is running
 And the data consists of one or more tasks
 When user requests for task x
 Then the correct task x is returned

Scenario: Retrieving all lists
 Given the data consists of one or more tasks
 When user requests for all tasks
 Then all tasks in database are returned

Scenario: Negative Test
 Given the component is not running
 When user requests for task x it fails with response 404

Snippet 9: En funktionsfil, der definerer BDD-tests

End-to-end tests

I lighed med komponenttests er formålet med disse ende-til-ende-test ikke at udføre kodedækning, men at sikre, at systemet opfylder de anmodede forretningsscenarier. Forskellen er, at ved end-to-end test er alle komponenter oppe og køre under testen.

I henhold til testpyramidediagrammet falder antallet af ende-til-ende-test yderligere under hensyntagen til den langsommelighed, de kan forårsage. Det første trin er at have opsætningen kørende, og i dette eksempel vil vi udnytte docker.

version: '3.7'
services:
    today-app:
        image: today-app:1
        container_name: "today-app"
        build:
          context: ./
          dockerfile: DockerFile
        environment:
           - SPRING_DATA_MONGODB_HOST=mongodb
        volumes:
          - /data/today-app
        ports:
          - "8082:8080"
        links:
          - mongodb
        depends_on:
          - mongodb

    mongodb:
        image: mongo:3.2
        container_name: "mongodb"
        restart: always
        environment:
           - AUTH=no
           - MONGO_DATA_DIR=/data/db
           - MONGO_LOG_DIR=/dev/log
        volumes:
           - ./data:/data
        ports:
           - 27017:27017
        command: mongod --smallfiles --logpath=/dev/null # --quiet

Snippet 10: Docker.yml-definitionen, der bruges til at implementere den definerede tjeneste og den specificerede version af mongo som containere

I henhold til komponenttests giver det mening at holde ende-til-ende-test i et separat modul og forskellige faser. exec-maven-plugin blev brugt til at implementere alle nødvendige komponenter, udføre vores tests og til sidst rense og rive ned vores testmiljø.

Da dette er en bred stack-test, vil et mindre udvalg af tests pr. funktion blive udført. Tests udvælges ud fra opfattet forretningsrisiko. De tidligere typer test dækkede detaljer på lavt niveau. Det betyder, om en brugerhistorie matcher acceptkriterierne. Disse test bør også øjeblikkeligt stoppe en udgivelse, da en fejl her kan forårsage alvorlige forretningsmæssige konsekvenser.

Konklusion

Handoff-centreret test ender ofte med at blive en meget lang proces, der tager op til uger, før alle fejl er identificeret, rettet og en ny implementering klar. Feedback modtages først efter en udgivelse, hvilket gør levetiden for en version af vores hurtigst mulige ekspeditionstid.

Den kontinuerlige testtilgang sikrer øjeblikkelig feedback. Det betyder, at DevOps-ingeniøren straks er klar over, om den implementerede funktion er produktionsklar eller ej, afhængigt af resultatet af de kørte test. Fra enhedstests op til ende-til-ende-tests hjælper de alle med at fremskynde vurderingsprocessen.

Microservices-arkitektur hjælper med at skabe hurtigere udrulninger til produktion, da den er domænedrevet. Det sikrer fejlisolering og øger ejerskabet. Når flere teams arbejder på det samme projekt, er det endnu en grund til at tage en sådan arkitektur i brug: For at sikre, at teams er uafhængige og ikke forstyrrer hinandens arbejde.

Forbedre testbarheden ved at gå i retning af kontinuerlig test. Hver mikrotjeneste har et veldefineret domæne, og dets omfang bør være begrænset til én aktør. De anvendte testcases er specifikke og mere kortfattede, og testene er isolerede, hvilket letter udgivelser og hurtigere implementeringer.

Efter TDD-tilgangen er der ingen kodning, medmindre en mislykket test vender tilbage. Denne proces øger tilliden, når en iterativ implementering resulterer i et vellykket forsøg. Denne proces indebærer, at test foregår parallelt med den faktiske implementering, og alle ovennævnte test udføres, før ændringer når et iscenesættelsesmiljø. Kontinuerlig test fortsætter med at udvikle sig, indtil den går ind i næste udgivelsesstadium, det vil sige et iscenesættelsesmiljø, hvor fokus skifter til mere udtømmende test såsom belastningstest.

Agile, DevOps og kontinuerlig levering kræver kontinuerlig test. Den vigtigste fordel er den umiddelbare feedback fra automatiserede tests. De mulige konsekvenser kan påvirke brugeroplevelsen, men også have højrisiko forretningsmæssige konsekvenser. For mere information om kontinuerlig test, kontakt phoenixNAP i dag.