Jatkuva testaus mikropalveluilla (esimerkein)


Milloin Microservice Architecture on oikea tie?

Oikean arkkitehtuurin valitseminen ja suunnittelu järjestelmälle on ratkaisevan tärkeää. Palveluvaatimusten laatu ja ei-toiminnallisten vaatimusten, kuten ylläpidettävyys, laajennettavuus ja testattavuus, käsittely on varmistettava.

Mikropalveluarkkitehtuuri on melko toistuva valinta uusimmissa ekosysteemeissä sen jälkeen, kun yritykset ovat ottaneet käyttöön Agilen ja DevOpsin. Vaikka se ei ole tosiasiallinen valinta, se on yksi suosituimmista vaihtoehdoista, kun käsitellään järjestelmiä, jotka kasvavat voimakkaasti ja joissa monoliittiarkkitehtuuria ei enää voida ylläpitää. Komponenttien pitäminen palvelukeskeisinä ja löyhästi kytkettyinä mahdollistaa jatkuvan kehitys- ja julkaisusyklin. Tämä saa yritykset jatkuvasti testaamaan ja päivittämään ohjelmistojaan.

Tärkeimmät edellytykset tällaiselle arkkitehtuurille ovat:

  • Verkkotunnuslähtöinen suunnittelu
  • Jatkuva toimitus ja DevOps-kulttuuri
  • Epäonnistumisen eristäminen
  • Hajauttaminen

Sillä on seuraavat edut:

  • Joukkueen omistus
  • Säännölliset julkaisut
  • Helpompi huolto
  • Helpommat päivitykset uudempiin versioihin
  • Teknologiaagnostikko

Sillä on seuraavat haitat:

  • mikropalveluiden väliset viestintämekanismit
  • Palvelujen määrän lisääminen lisää järjestelmän yleistä monimutkaisuutta

Mitä hajautetumpi ja monimutkaisempi arkkitehtuuri on, sitä haastavampaa on varmistaa, että järjestelmää voidaan laajentaa ja ylläpitää samalla kun kustannukset ja riskit hallitaan. Yksi liiketapahtuma voi sisältää useita protokollien ja tekniikoiden yhdistelmiä. Kyse ei ole vain käyttötapauksista, vaan myös sen toiminnasta. Agile- ja DevOps-lähestymistapoja otettaessa tulee löytää tasapaino joustavuuden ja toiminnallisuuden välillä jatkuvan päivityksen ja testauksen saavuttamiseksi.

Testausstrategioiden merkitys suhteessa mikropalveluihin

DevOpsin käyttöönotto organisaatiossa pyrkii eliminoimaan eri eristyneitä osastoja ja siirtymään kohti yhtä kokonaisvaltaista tiimiä. Tällä siirrolla pyritään erityisesti parantamaan ohjelmistotiimin ja toimintatiimin välisiä suhteita ja prosesseja. Nopeampi toimitus tarkoittaa myös jatkuvan testauksen varmistamista osana ohjelmistojen toimitusprosessia. Päivittäinen (ja joissakin tapauksissa jopa parin tunnin välein) käyttöönotto on yksi tärkeimmistä tavoitteista nopeassa päästä päähän -yritysratkaisujen toimittamiselle. Luotettavuus ja turvallisuus on pidettävä tässä mielessä, ja tässä on testaus.

Testilähtöisen kehityksen sisällyttäminen on ainoa tapa saavuttaa aito luottamus siihen, että koodi on tuotantovalmis. Kelvolliset testitapaukset lisäävät arvoa järjestelmälle, koska ne validoivat ja dokumentoivat itse järjestelmän. Tämän lisäksi hyvä koodin kattavuus rohkaisee parannuksiin ja auttaa uudelleenmuodostuksessa.

Mikropalveluarkkitehtuuri hajauttaa viestintäkanavat, mikä tekee testauksesta monimutkaisempaa. Se ei ole ylitsepääsemätön ongelma. Mikropalvelun omistavan tiimin ei pitäisi pelätä muutosten tekemistä, koska ne saattavat rikkoa olemassa olevia asiakassovelluksia. Manuaalinen testaus on erittäin tehotonta, kun otetaan huomioon, että jatkuva integrointi ja jatkuva käyttöönotto ovat tämän hetken paras käytäntö. DevOps-insinöörien tulee varmistaa, että automaatiotestit sisällytetään kehitystyönkulkuunsa: kirjoita testejä, lisää/muuta koodia ja suorita testejä.

Yleiset mikropalvelutestausmenetelmät

Testipyramidi on helppo konsepti, joka auttaa tunnistamaan testien kirjoittamisen vaatiman vaivan ja sen, mihin testien määrän pitäisi laskea, jos rakeisuus pienenee. Se pätee myös silloin, kun harkitaan jatkuvaa mikropalvelujen testausta.

Aiheen konkretisoimiseksi käsittelemme esimerkkimikropalvelun testausta Spring Bootilla ja Javalla. Mikropalveluarkkitehtuurit ovat rakenteeltaan monimutkaisempia kuin monoliittinen arkkitehtuuri. Siitä huolimatta keskitymme jatkossakin testityyppiin emmekä arkkitehtuuriin. Katkelmamme perustuvat minimaaliseen projektiin, joka koostuu yhdestä API-pohjaisesta mikropalvelusta, joka omistaa MongoDB:tä käyttävän tietosäilön.

Yksikkötestit

Yksikkötestien tulisi olla suurin osa testeistä, koska ne ovat nopeita, luotettavia ja helppoja ylläpitää. Näitä testejä kutsutaan myös valkoisen laatikon testeiksi. Niitä toteuttava insinööri tuntee logiikan ja kirjoittaa testin vahvistaakseen moduulin tekniset tiedot ja tarkistaakseen koodin laadun.

Näiden testien painopiste on pieni osa järjestelmää erillään, eli Class Under Test (CUT). Yhden vastuun periaate on hyvä ohje toiminnallisuuteen liittyvän koodin hallinnassa.

Yksikkötestin yleisin muoto on "yksinäinen yksikkötesti". ”Se ei ylitä mitään rajoja eikä tarvitse yhteistyökumppaneita CUT:n lisäksi.

Kuten Bill Caputo hahmotteli, tietokannat, viestintäkanavat tai muut järjestelmät ovat rajana; mikä tahansa CUT:n käyttämä tai vaatima lisäluokka on yhteistyökumppani. Yksikkötesti ei saa koskaan ylittää rajoja. Yhteistyökumppaneita käytettäessä kirjoitetaan ”seuraava yksikkötestit. ” CUT:n käyttämien riippuvuuksien pilkkaaminen on tapa testata seurallista koodia "yksinäisen yksikön testillä". ”

Perinteisissä ohjelmistokehitysmalleissa kehittäjien testausta ei vielä otettu villisti käyttöön, vaan se piti testata täysin off-sync-synkronisesti kehityksestä. Korkean koodin peittoluokituksen saavuttamista pidettiin testiohjelmiston luottamuksen avainindikaattorina.

Ketterän ja lyhyiden iteratiivisten syklien käyttöönoton myötä on nyt selvää, että aiemmat testimallit eivät enää toimi. Toistuvia muutoksia odotetaan jatkuvasti. On paljon tärkeämpää testata havaittavaa toimintaa sen sijaan, että kaikki koodipolut katettaisiin. Yksikkötestien tulisi olla enemmän väitteitä kuin koodin kattavuutta, koska tarkoituksena on varmistaa, että logiikka toimii odotetulla tavalla.

On hyödytöntä olla komponentti, jossa on paljon testejä ja suuri prosenttiosuus koodin peitosta, kun testeillä ei ole kunnon väitteitä. BDD (Behavior-Driven Development) -lähestymistavan soveltaminen varmistaa, että testit varmistavat lopputilan ja että käyttäytyminen vastaa yrityksen asettamia vaatimuksia. Kohdennettujen testien, joiden laajuus on hyvin määritelty, etuna on, että epäonnistumisen syy on helpompi tunnistaa. BDD-testit antavat meille enemmän luottamusta siihen, että epäonnistuminen johtui ominaisuuksien käyttäytymisen muutoksesta. Testit, jotka muutoin keskittyvät enemmän koodin kattamiseen, eivät voi tarjota paljon luottamusta, koska on suurempi riski, että epäonnistuminen johtuisi itse testeissä tehdyistä muutoksista koodipolkujen toteutustietojen vuoksi.

Testien tulee noudattaa Martin Fowlerin ehdotusta, kun hän totesi seuraavan (julkaisussa Refactoring: Improving the Design of Existing Code, toinen painos. Kent Beck ja Martin Fowler. Addison-Wesley. 2018):

Toinen syy keskittyä vähemmän pieniin toteutusyksityiskohtiin on refaktorointi. Uudelleenjärjestelyn aikana yksikkötestien tulee antaa meille luottamusta eivätkä hidastaa työtä. Muutos yhteiskäyttäjän toteutuksessa voi johtaa testivirheeseen, mikä voi vaikeuttaa testien ylläpitoa. On erittäin suositeltavaa pitää mahdollisimman vähän seurallisia yksikkötestejä. Tämä pätee erityisesti silloin, kun tällaiset testit saattavat hidastaa kehitystyön elinkaarta, jolloin testit jäävät huomiotta. Erinomainen tilanne seurallisen yksikkötestin sisällyttämiselle on negatiivinen testi, varsinkin kun käsitellään käyttäytymisen todentamista.

Integraatiotestit

Yksi mikropalvelujen merkittävimmistä haasteista on testata niiden vuorovaikutusta muiden infrastruktuuripalvelujen kanssa eli rajojen, joista CUT riippuu, kuten tietokannat tai muut palvelut. Testipyramidi osoittaa selvästi, että integrointitestien tulisi olla vähemmän kuin yksikkötestejä, mutta enemmän kuin komponentteja ja päästä päähän -testejä. Nämä muun tyyppiset testit voivat olla hitaampia, vaikeampia kirjoittaa ja ylläpitää ja olla melko hauraita verrattuna yksikkötesteihin. Rajojen ylittäminen saattaa vaikuttaa suorituskykyyn ja suoritusaikaan verkko- ja tietokantakäytön vuoksi. Silti ne ovat välttämättömiä, etenkin DevOps-kulttuurissa.

Jatkuvassa käyttöönotossa suositaan kapeita integraatiotestejä laajojen integraatiotestien sijaan. Jälkimmäinen on hyvin lähellä päästä päähän -testejä, joissa se vaatii todellisen palvelun olevan käynnissä eikä näiden palvelujen testikaksoisosan käyttöä koodivuorovaikutusten testaamiseen. Päätavoitteena on rakentaa hallittavia operatiivisia testejä nopeasti, helposti ja joustavasti. Integrointitestit keskittyvät CUT:n vuorovaikutukseen yhden palvelun kanssa kerrallaan. Keskitymme kapeisiin integraatiotesteihin. Palveluparin välisen vuorovaikutuksen todentaminen voidaan varmistaa odotetusti, kun palvelut voivat olla joko infrastruktuuripalveluita tai mitä tahansa muuta palvelua.

Pysyvyystestit

>

Kiistanalainen testityyppi on pysyvyyskerroksen testaus, jonka ensisijaisena tavoitteena on testata kyselyitä ja vaikutusta testitietoihin. Yksi vaihtoehto on käyttää muistissa olevia tietokantoja. Jotkut saattavat pitää muistissa olevien tietokantojen käyttöä seurallisena yksikkötestinä, koska se on itsenäinen testi, idempotentti ja nopea. Testi suoritetaan tietokannassa, joka on luotu halutulla kokoonpanolla. Kun testiajot ja väitteet on tarkistettu, tietovarasto puhdistetaan automaattisesti, kun JVM poistuu sen lyhytaikaisen luonteen vuoksi. Muista, että yhteys toiseen palveluun on edelleen kesken, ja sitä pidetään kapeana integrointitestinä. Test Driven Development (TDD) -lähestymistavassa tällaiset testit ovat välttämättömiä, koska testipakettien pitäisi suorittaa sekunneissa. Muistissa olevat tietokannat ovat kelvollinen kompromissi sen varmistamiseksi, että testit pidetään mahdollisimman nopeasti, eikä niitä jätetä huomiotta pitkällä aikavälillä.

@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();
   }
}

Katkelma 1: In-memory MongoDB:n asennus ja käynnistys

Yllä oleva ei ole täydellinen integrointitesti, koska muistissa oleva tietokanta ei toimi täsmälleen kuten tuotantotietokantapalvelin. Siksi se ei ole kopio "todelliselle" mongopalvelimelle, mikä olisi tilanne, jos valittaisiin laajat integraatiotestit.

Toinen vaihtoehto pysyvyyden integrointitesteille on suorittaa laajat testit yhdistettynä varsinaiseen tietokantapalvelimeen tai käyttämällä säiliöitä. Kontit helpottavat tuskaa, koska pyynnöstä tietokanta varustetaan kiinteään palvelimeen verrattuna. Muista, että tällaiset testit vievät aikaa, ja testien luokittelu on mahdollinen ratkaisu. Koska nämä testit riippuvat toisesta CUT:n lisäksi toimivasta palvelusta, sitä pidetään järjestelmätestinä. Nämä testit ovat edelleen välttämättömiä, ja luokkien avulla voidaan paremmin määrittää, milloin tietyt testit tulisi suorittaa, jotta kustannusten ja arvon välillä saadaan paras tasapaino. Esimerkiksi kehityssyklin aikana voidaan suorittaa vain kapeita integraatiotestejä käyttämällä muistissa olevaa tietokantaa. Yöversiot voisivat myös suorittaa testejä, jotka kuuluvat johonkin luokkaan, kuten laajaan integraatiotesteihin.

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

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

Katkelma 2: Luokkien käyttäminen integrointitestien tyyppien erottamiseen

Kuluttajalähtöiset testit

Inter-Process Communication (IPC) -mekanismit ovat yksi mikropalveluarkkitehtuuriin perustuvien hajautettujen järjestelmien keskeinen osa. Tämä asennus aiheuttaa erilaisia komplikaatioita testisarjojen luomisen aikana. Tämän lisäksi ketterässä tiimissä muutoksia tehdään jatkuvasti, mukaan lukien muutokset API:ihin tai tapahtumiin. Riippumatta siitä, mitä IPC-mekanismia järjestelmä käyttää, kahden palvelun välillä on sopimus. Sopimuksia on monenlaisia riippuen siitä, mitä mekanismia järjestelmässä käytetään. Sovellusliittymiä käytettäessä sopimus on HTTP-pyyntö ja vastaus, kun taas tapahtumapohjaisessa järjestelmässä sopimus on itse toimialueen tapahtuma.

Ensisijainen tavoite mikropalveluita testattaessa on varmistaa, että kyseiset sopimukset ovat hyvin määriteltyjä ja vakaita milloin tahansa. TDD:n ylhäältä alas -lähestymistavassa nämä ovat ensimmäiset katettavat testit. Perusteellinen integraatiotesti varmistaa, että kuluttaja saa nopeaa palautetta heti, kun asiakas ei vastaa puhuttavan tuottajan todellista tilaa.

Näiden testien tulisi olla osa säännöllistä käyttöönottoprosessia. Niiden epäonnistuminen antaisi kuluttajille mahdollisuuden saada tieto siitä, että tuottajapuolella on tapahtunut muutos ja että muutoksia tarvitaan, jotta johdonmukaisuus saadaan jälleen aikaan. Ilman tarvetta kirjoittaa monimutkaisia päästä päähän -testejä, "kuluttajalähtöinen sopimustestaus" kohdistuisi tähän käyttötapaukseen.

Seuraavassa on esimerkki spring-cloud-contract-laajennuksen luomasta sopimusvahvistimesta.

@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");
}

Katkelma 3: Spring-cloud-contract-laajennuksen automaattisesti luoma sopimusvahvistin

Tuottajaan kirjoitettu BaseClass ohjeistaa, millaista vastausta voidaan odottaa erityyppisiin pyyntöihin käyttämällä itsenäistä asennusta. Pakattu tykkikokoelma on kaikkien kuluttajien käytettävissä, jotta ne voivat vetää niitä käyttöönsä. Monimutkaisuus syntyy, kun useat kuluttajat käyttävät samaa sopimusta; siksi tuottajalla on oltava kokonaiskuva vaadituista palvelusopimuksista.

@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));
		
	}

Katkelma 4: tuottajan BaseClass, joka määrittää kunkin pyynnön odotetun vastauksen

Kuluttajapuolella kevät-pilvi-käynnistin-sopimus-stub-runner-riippuvuus sisällytettiin, joten määritimme testin käyttämään stubs-binääriä. Tämä testi suoritetaan käyttämällä tuottajan luomia tyngöitä kokoonpanon mukaan, jonka versio on määritetty tai aina uusin. Tynkä artefakti yhdistää asiakkaan tuottajaan varmistaakseen, että molemmat työskentelevät saman sopimuksen mukaisesti. Mikä tahansa tapahtuva muutos heijastuisi näihin testeihin, ja siten kuluttaja tunnistaisi, onko tuottaja muuttunut vai ei.

@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");
		. . . 
		
	}
}

Katkelma 5: Kuluttaja lisää tuottajan määrittämän tynkäversion

Tällaiset integrointitestit varmistavat, että palveluntarjoajan API on edelleen kuluttajien odotusten mukainen. Käytettäessä sovellusliittymien pilkattuja yksikkötestejä olisimme tukahduttaneet API:t ja pilkanneet toimintaa. Kuluttajan näkökulmasta tämäntyyppiset testit varmistavat, että asiakas vastaa odotuksiamme. On tärkeää huomata, että jos tuottajapuoli muuttaa API:ta, testit eivät epäonnistu. Ja on välttämätöntä määritellä, mitä testi kattaa.

// 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");

Katkelma 6: kuluttajatesti, joka tekee väitteitä omasta määritellystä vastauksestaan

Komponenttitestit

Mikropalveluarkkitehtuuri voi kasvaa nopeasti, joten testattava komponentti saattaa integroitua useisiin muihin komponentteihin ja useisiin infrastruktuuripalveluihin. Tähän asti olemme kattaneet valkoisen laatikon testauksen yksikkötesteillä ja kapeilla integraatiotesteillä testataksemme CUT:n rajan ylittävää integrointia toiseen palveluun.

Nopein komponenttien testaustyyppi on prosessin sisäinen lähestymistapa, jossa testauskaksojen ja muistin tietovarastojen käytön ohella testaus pysyy rajojen sisällä. Tämän lähestymistavan suurin haittapuoli on, että käyttöön otettavaa tuotantopalvelua ei ole täysin testattu; päinvastoin, komponentti vaatii muutoksia sovelluksen kytkemiseksi eri tavalla. Suositeltu menetelmä on prosessin ulkopuolisten komponenttien testaus. Nämä ovat kuin päästä päähän -testejä, mutta kun kaikki ulkoiset yhteistyökumppanit on vaihdettu testituplaan, se harjoittelee siten täysin käyttöön otettua artefaktia hyödyntäen todellisia verkkopuheluita. Testi olisi vastuussa siitä, että kaikki ulkoiset palvelut määritetään oikein tyngiksi.

@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();
}
}

Katkelma 7: Luettelon käyttöönotto CloudFoundryssa ja kaikki testien edellyttämät kutsut

Cloud Foundry on yksi vaihtoehdoista, joita käytetään konttipohjaisissa testausarkkitehtuureissa. "Se on avoimen lähdekoodin pilvisovellusalusta, joka tekee sovellusten rakentamisesta, testaamisesta, käyttöönotosta ja skaalaamisesta nopeampaa ja helpompaa. ” Seuraava on manifest.yml, tiedosto, joka määrittää kaikkien järjestelmän sovellusten määritykset. Tätä tiedostoa käytetään todellisen palvelun käyttöönottoon tuotantovalmiissa muodossa Pivotal-organisaation tilassa, jossa MongoDB-palvelu on jo määritetty tuotantoversiota vastaavasti.

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

Katkelma 8: Palvelun yhden esiintymän käyttöönotto mongo-palvelusta riippuen

Kun valitset prosessin ulkopuolisen lähestymistavan, muista, että todellisia rajoja testataan, ja näin ollen testit ovat hitaampia, koska siellä on verkko- ja tietokantavuorovaikutuksia. Olisi ihanteellista, että nämä testisarjat kirjoitettaisiin erillisessä moduulissa. Jotta niitä voidaan ajaa erikseen eri maven-vaiheessa tavallisen "testi"-vaiheen sijaan.

Koska testien painopiste on itse komponentissa, testit kattavat komponentin ensisijaiset vastuut, mutta laiminlyövät tarkoituksellisesti kaikki muut järjestelmän osat.

Kurkku, ohjelmistotyökalu, joka tukee Behavior-Driven Developmentia, on vaihtoehto tällaisten käyttäytymistestien määrittämiseen. Selkeän kielen jäsentimen, Gherkin, avulla se varmistaa, että asiakkaat ymmärtävät helposti kaikki kuvatut testit. Seuraava Cucumber-ominaisuustiedosto varmistaa, että komponenttitoteutus vastaa kyseisen ominaisuuden liiketoimintavaatimuksia.

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

Katkelma 9: BDD-testejä määrittelevä ominaisuustiedosto

Päästä päähän -testit

Samoin kuin komponenttitestien, näiden päästä päähän -testien tarkoituksena ei ole suorittaa koodin peittoa, vaan varmistaa, että järjestelmä täyttää vaaditut liiketoimintaskenaariot. Erona on, että päästä päähän -testauksessa kaikki komponentit ovat toiminnassa testin aikana.

Testauspyramidikaavion mukaan päästä päähän -testien määrä laskee edelleen, kun otetaan huomioon niiden aiheuttama hitaus. Ensimmäinen vaihe on käynnistää asennus, ja tässä esimerkissä hyödynnämme dockeria.

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

Katkelma 10: Docker.yml-määritelmä, jota käytetään määritetyn palvelun ja määritetyn mongon version käyttöönottamiseksi säilöinä

Komponenttitestien mukaan on järkevää pitää päästä päähän -testit erillisessä moduulissa ja eri vaiheissa. exec-maven-plugin:lla otettiin käyttöön kaikki vaaditut komponentit, suoritettiin testimme ja lopuksi puhdistettiin ja purettiin testiympäristömme.

Koska tämä on laajapinoinen testi, suoritetaan pienempi valikoima testejä ominaisuutta kohti. Testit valitaan koetun liiketoimintariskin perusteella. Aiemmat testityypit kattoivat matalan tason yksityiskohdat. Tämä tarkoittaa, vastaako käyttäjän tarina hyväksymiskriteerejä. Näiden testien tulisi myös keskeyttää julkaisu välittömästi, koska epäonnistuminen tässä voi aiheuttaa vakavia seurauksia liiketoiminnalle.

Johtopäätös

Handoff-keskeinen testaus on usein erittäin pitkä prosessi, joka kestää jopa viikkoja, ennen kuin kaikki virheet tunnistetaan, korjataan ja uusi käyttöönotto on valmis. Palautetta saadaan vasta julkaisun jälkeen, mikä tekee versiomme elinkaaren nopeimman mahdollisen läpimenoajan.

Jatkuva testaustapa takaa välittömän palautteen. Tämä tarkoittaa, että DevOps-insinööri on välittömästi tietoinen siitä, onko toteutettu ominaisuus tuotantovalmis vai ei, riippuen testien tuloksista. Yksikkötesteistä päästä päähän -testeihin ne kaikki auttavat nopeuttamaan arviointiprosessia.

Mikropalveluarkkitehtuuri auttaa luomaan nopeampia käyttöönottoja tuotantoon, koska se on toimialuelähtöinen. Se varmistaa vikaeristyksen ja lisää omistajuutta. Kun useat tiimit työskentelevät saman projektin parissa, se on toinen syy ottaa käyttöön tällainen arkkitehtuuri: Varmistaa, että tiimit ovat riippumattomia eivätkä häiritse toistensa työtä.

Paranna testattavuutta siirtymällä kohti jatkuvaa testausta. Jokaisella mikropalvelulla on hyvin määritelty toimialue, ja sen laajuus tulisi rajoittaa yhteen toimijaan. Käytetyt testitapaukset ovat tarkkoja ja ytimekkäämpiä, ja testit ovat erillisiä, mikä helpottaa julkaisuja ja nopeampaa käyttöönottoa.

TDD-lähestymistavan mukaisesti koodausta ei tapahdu, ellei epäonnistunut testi palaa. Tämä prosessi lisää luottamusta, kun iteratiivinen toteutus johtaa onnistuneeseen kokeiluun. Tämä prosessi tarkoittaa, että testaus tapahtuu rinnakkain varsinaisen toteutuksen kanssa ja kaikki yllä mainitut testit suoritetaan ennen kuin muutokset saavuttavat lavastusympäristön. Jatkuva testaus kehittyy, kunnes se siirtyy seuraavaan julkaisuvaiheeseen eli lavastusympäristöön, jossa painopiste siirtyy kattavampaan testaukseen, kuten kuormitustestaukseen.

Ketterä, DevOps ja jatkuva toimitus edellyttävät jatkuvaa testausta. Tärkein etu on automaattisista testeistä saatu välitön palaute. Mahdolliset vaikutukset voivat vaikuttaa käyttökokemukseen, mutta niillä voi olla myös riskialttiita seurauksia liiketoiminnalle. Jos haluat lisätietoja jatkuvasta testauksesta, ota yhteyttä phoenixNAPiin jo tänään.