Yksikkötestaus - Unit testing

In ohjelmointi , yksikkö testaus on ohjelmiston testaus menetelmä, jonka avulla yksittäiset yksiköt lähdekoodin -sets yhden tai useamman tietokoneohjelman moduulit yhdessä niihin liittyvien ohjausdatan, käyttö menettelyjä , ja toimintatavat-testataan sen määrittämiseksi, ovatko ne sopivat käytettäviksi .

Kuvaus

Yksikkötestit ovat tyypillisesti ohjelmistokehittäjien kirjoittamia ja suorittamia automatisoituja testejä sen varmistamiseksi, että sovelluksen osa (joka tunnetaan nimellä "yksikkö") täyttää sen suunnittelun ja käyttäytyy suunnitellusti. In menettelyyn ohjelmointi , yksikkö voi olla kokonainen moduuli, mutta se on yleisesti yksilöllinen toiminta tai menettelyä. In olio-ohjelmointi , yksikkö on usein koko rajapinnan, kuten luokan tai yksittäisen menetelmällä. Kirjoittamalla testit ensin pienimmille testattaville yksiköille ja sitten niiden välisten yhdistettyjen käyttäytymismallien muodostamiseksi voidaan rakentaa kattavia testejä monimutkaisille sovelluksille.

Esiintyvien ongelmien erottamiseksi jokainen testitapaus on testattava itsenäisesti. Korvaavia aineita, kuten menetelmän tynnyriä , pilkkaa esineitä , väärennöksiä ja testivaljaita, voidaan käyttää moduulin testaamiseen erikseen.

Kehityksen aikana ohjelmistokehittäjä voi koodata kriteerit tai tulokset, joiden tiedetään olevan hyviä, testiin yksikön oikeellisuuden varmistamiseksi. Testitapauksen suorituksen aikana kehykset kirjaavat testit, jotka eivät täytä kriteerejä, ja raportoivat niistä yhteenvedossa. Tätä varten yleisimmin käytetty lähestymistapa on testi - funktio - odotettu arvo.

Yksikkötestien kirjoittaminen ja ylläpito voidaan tehdä nopeammin parametrisoiduilla testeillä . Nämä mahdollistavat yhden testin suorittamisen useita kertoja eri syötesarjoilla, mikä vähentää testikoodin päällekkäisyyttä. Toisin kuin perinteiset yksikkötestit, jotka ovat yleensä suljettuja menetelmiä ja testattavat muuttamattomat olosuhteet, parametrisoidut testit ottavat kaikki parametrit. Parametroituja testejä tukevat TestNG , JUnit ja sen .Net-vastine XUnit . Sopivat parametrit yksikötesteille voidaan toimittaa manuaalisesti tai joissakin tapauksissa testikehys luo ne automaattisesti. Viime vuosina on lisätty tukea tehokkaampien (yksikkö) testien kirjoittamiseen, teorioiden käsitteen hyödyntämiseen, testitapauksiin, joissa suoritetaan samat vaiheet, mutta suorituksen aikana luotuihin testitietoihin, toisin kuin tavallisissa parametrisoiduissa testeissä, joissa käytetään samoja suoritusvaiheita syötesarjojen kanssa jotka ovat ennalta määriteltyjä.

Edut

Yksikkötestauksen tavoitteena on eristää jokainen ohjelman osa ja osoittaa, että yksittäiset osat ovat oikeita. Yksikkötesti antaa tiukan, kirjallisen sopimuksen , jonka koodinpätkän on täytettävä. Tämän seurauksena siitä on useita etuja.

Yksikkötestaus löytää ongelmia varhaisessa kehitysvaiheessa . Tämä sisältää sekä ohjelmoijan toteuttamisen virheitä että yksikön spesifikaation virheitä tai puuttuvia osia. Perusteellisen testisarjan kirjoittaminen pakottaa kirjoittajan miettimään panoksia, lähtöjä ja virhetilanteita ja siten määrittelemään yksiselitteisemmin yksikön halutun käyttäytymisen. Virheen löytämisen kustannukset ennen koodauksen aloittamista tai kun koodi kirjoitetaan ensimmäisen kerran, ovat huomattavasti pienemmät kuin virheen havaitsemisen, tunnistamisen ja korjaamisen kustannukset myöhemmin. Virheet julkaistussa koodissa voivat myös aiheuttaa kalliita ongelmia ohjelmiston loppukäyttäjille. Koodi voi olla mahdotonta tai vaikea testata yksikköä, jos se on kirjoitettu huonosti, joten yksikön testaus voi pakottaa kehittäjät rakentamaan funktioita ja objekteja paremmin.

In testivetoinen kehitys (TDD), jota käytetään usein sekä äärimmäisen ohjelmointi ja tungosta , laite testejä on luotu ennen kuin koodi itse on kirjoitettu. Kun testit läpäisevät, kyseisen koodin katsotaan olevan täydellinen. Samat yksikötestit suoritetaan tätä funktiota vastaan ​​usein, kun suurempi koodipohja kehitetään joko koodin muuttuessa tai automatisoidun prosessin avulla rakennuksen kanssa. Jos yksikötestit epäonnistuvat, sitä pidetään virhenä joko muutetussa koodissa tai itse testeissä. Yksikkötestit mahdollistavat sitten vian tai vian sijainnin helpon jäljittämisen. Koska yksikötestit ilmoittavat kehitystiimille ongelmasta ennen koodin luovuttamista testaajille tai asiakkaille, mahdolliset ongelmat tarttuvat kehitysprosessin alkuvaiheessa.

Yksikkötestaus sallii ohjelmoija Refactor koodin tai päivittää järjestelmän kirjastot myöhemmin, ja varmista, että moduuli toimii edelleen oikein (esimerkiksi vuonna regressiotestaus ). Menettely on kirjoittaa testitapauksia kaikille toiminnoille ja menetelmille, jotta aina, kun muutos aiheuttaa vian, se voidaan tunnistaa nopeasti. Yksikkötestit havaitsevat muutokset, jotka voivat rikkoa suunnittelusopimuksen .

Yksikkötestaus voi vähentää epävarmuutta yksiköissä itsessään, ja sitä voidaan käyttää alhaalta ylöspäin suuntautuvan testauksen tyyliin. Testaamalla ensin ohjelman osat ja sitten sen osien summa, integraatiotestaus on paljon helpompaa.

Yksikkötestaus tarjoaa eräänlaisen elävän dokumentaation järjestelmästä. Kehittäjät, jotka haluavat oppia, mitä toimintoja yksikkö tarjoaa ja miten sitä voidaan käyttää, voivat tarkastella yksikön testejä saadakseen perustiedot yksikön käyttöliittymästä ( API ).

Yksikkö testitapaukset ilmentävät ominaisuuksia, jotka ovat kriittisiä onnistumisen yksikön. Nämä ominaisuudet voivat osoittaa yksikön asianmukaista / epäasiallista käyttöä sekä negatiivisia käyttäytymismalleja, jotka yksikkö joutuu loukkuun. Yksikkötestitapaukset itsessään dokumentoivat nämä kriittiset ominaisuudet, vaikka monet ohjelmistokehitysympäristöt eivät tukeudu vain koodiin kehitettävän tuotteen dokumentoimiseksi.

Kun ohjelmistoa kehitetään käyttäen testipohjaista lähestymistapaa, muodollisen suunnittelun sijasta voidaan yhdistää yksikkötestin kirjoittaminen käyttöliittymän määrittelemiseksi sekä testin jälkeen suoritetut korjaustoiminnot. Jokainen yksikkökoe voidaan nähdä suunnitteluelementtinä, joka määrittelee luokat, menetelmät ja havaittavan käyttäytymisen.

Rajoitukset ja haitat

Testaus ei tavoita kaikkia ohjelman virheitä, koska se ei voi arvioida kaikkia suoritusreittejä muissa kuin vähäisimmissä ohjelmissa. Tämä ongelma on pysäytysongelman pääjoukko , jota ei voida ratkaista . Sama pätee yksikkötestaukseen. Lisäksi yksiköiden testaus määritelmän mukaan testaa vain yksiköiden itsensä toimivuuden. Siksi se ei havaitse integraatiovirheitä tai laajempia järjestelmätason virheitä (kuten toimintoja, jotka suoritetaan useilla yksiköillä, tai ei-toiminnallisia testialueita, kuten suorituskyky ). Yksikkötestaus tulisi tehdä yhdessä muiden ohjelmistojen testaustoimintojen kanssa , koska ne voivat osoittaa vain tiettyjen virheiden esiintymisen tai puuttumisen; ne eivät voi osoittaa virheiden täydellistä puuttumista. Jokaisen suorituspolun ja mahdollisen syötteen oikean toiminnan takaamiseksi ja virheiden puuttumisen varmistamiseksi tarvitaan muita tekniikoita, nimittäin muodollisten menetelmien soveltamista sen osoittamiseksi, että ohjelmistokomponentilla ei ole odottamatonta toimintaa.

Yksilötestien monimutkainen hierarkia ei ole sama kuin integraatiotestaus. Integrointi oheislaitteiden kanssa tulisi sisällyttää integraatiotesteihin, mutta ei yksikkötesteihin. Integraatiotestaus perustuu tyypillisesti edelleen vahvasti siihen, että ihmiset testaavat manuaalisesti ; korkean tason tai globaalia testausta voi olla vaikea automatisoida, jolloin manuaalinen testaus näyttää usein nopeammalta ja halvemmalta.

Ohjelmistojen testaus on yhdistävä ongelma. Esimerkiksi jokainen Boolen päätöslauselma vaatii vähintään kaksi testiä: yhden, jonka tulos on "tosi" ja toisen "väärä". Tämän seurauksena jokaiselle kirjoitetulle koodiriville ohjelmoijat tarvitsevat usein 3-5 riviä testikoodia. Tämä vie tietysti aikaa, ja sen sijoitus ei ehkä ole vaivan arvoista. On ongelmia, joita ei voida helposti testata lainkaan - esimerkiksi ne, jotka eivät ole deterministisiä tai joihin liittyy useita ketjuja . Lisäksi yksikkötestin koodi on todennäköisesti vähintään yhtä viallinen kuin testattava koodi. Fred Brooks vuonna Myyttinen Man-Month lainausmerkkejä: "Ei koskaan lähteä merelle kahdella chronometers, ottaa yksi tai kolme." Jos kaksi kronometriä on ristiriidassa, mistä tiedät, mikä on oikea?

Toinen yksikkötestien kirjoittamiseen liittyvä haaste on realististen ja hyödyllisten testien asettamisen vaikeus. On luotava asiaankuuluvat alkuehdot, jotta testattava sovelluksen osa käyttäytyy kuin osa koko järjestelmää. Jos näitä alkuehtoja ei ole asetettu oikein, testi ei käytä koodia realistisessa kontekstissa, mikä heikentää yksikkötestitulosten arvoa ja tarkkuutta.

Yksikkötestauksen aiottujen hyötyjen saamiseksi tarvitaan tiukkaa kurinalaisuutta koko ohjelmistokehitysprosessin ajan. On välttämätöntä pitää huolellinen kirjaus paitsi suoritetuista testeistä, myös kaikista muutoksista, jotka on tehty tämän tai minkä tahansa muun ohjelmiston yksikön lähdekoodiin. Käyttö versionhallinta on olennainen. Jos yksikön myöhempi versio epäonnistuu tietyssä sen aiemmin läpäissyssä testissä, versionhallintaohjelmisto voi tarjota luettelon lähdekoodimuutoksista (jos sellaisia ​​on), joita laitteeseen on sovellettu tuon ajan jälkeen.

On myös välttämätöntä toteuttaa kestävä prosessi sen varmistamiseksi, että testitapausten virheet tarkistetaan säännöllisesti ja niihin puututaan välittömästi. Jos tällaista prosessia ei toteuteta ja se juurrutetaan tiimin työnkulkuun, sovellus kehittyy synkronoimatta yksikkötestipaketin kanssa, mikä lisää vääriä positiivisia tuloksia ja vähentää testipaketin tehokkuutta.

Sulautetun järjestelmäohjelmiston yksikkötestaus on ainutlaatuinen haaste: Koska ohjelmistoa kehitetään eri alustalla kuin sillä, jota se lopulta käyttää, et voi suorittaa testiohjelmaa varsinaisessa käyttöympäristössä, kuten työpöytäohjelmien kanssa on mahdollista.

Yksikkötestit ovat yleensä helpoimpia, kun menetelmällä on tuloparametrit ja jonkin verran lähtöä. Yksikkötestien luominen ei ole niin helppoa, kun menetelmän päätehtävänä on olla vuorovaikutuksessa jonkin sovelluksen ulkopuolisen kanssa. Esimerkiksi menetelmä, joka toimii tietokannan kanssa, saattaa vaatia mallin luomisen tietokannan vuorovaikutuksista, mikä ei todennäköisesti ole yhtä kattava kuin todelliset tietokannan vuorovaikutukset.

Esimerkki

Tässä on joukko Java- testitapauksia, jotka määrittävät useita toteutuksen elementtejä. Ensinnäkin, että on oltava rajapinta nimeltä Adder, ja toteutusluokka, jossa on nollargumenttirakentaja nimeltä AdderImpl. Se jatkuu assert että lisääjä käyttöliittymän pitäisi olla kutsuttua menetelmää lisäosa, jossa on kaksi kokonaisluku parametrit, joka palauttaa toisen kokonaisluvun. Se määrittelee myös tämän menetelmän käyttäytymisen pienelle arvoalueelle useilla testimenetelmillä.

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class TestAdder {

    @Test
    public void testSumPositiveNumbersOneAndOne() {
        Adder adder = new AdderImpl();
        assertEquals(2, adder.add(1, 1));
    }

    // can it add the positive numbers 1 and 2?
    @Test
    public void testSumPositiveNumbersOneAndTwo() {
        Adder adder = new AdderImpl();
        assertEquals(3, adder.add(1, 2));
    }

    // can it add the positive numbers 2 and 2?
    @Test
    public void testSumPositiveNumbersTwoAndTwo() {
        Adder adder = new AdderImpl();
        assertEquals(4, adder.add(2, 2));
    }

    // is zero neutral?
    @Test
    public void testSumZeroNeutral() {
        Adder adder = new AdderImpl();
        assertEquals(0, adder.add(0, 0));
    }

    // can it add the negative numbers -1 and -2?
    @Test
    public void testSumNegativeNumbers() {
        Adder adder = new AdderImpl();
        assertEquals(-3, adder.add(-1, -2));
    }

    // can it add a positive and a negative?
    @Test
    public void testSumPositiveAndNegative() {
        Adder adder = new AdderImpl();
        assertEquals(0, adder.add(-1, 1));
    }

    // how about larger numbers?
    @Test
    public void testSumLargeNumbers() {
        Adder adder = new AdderImpl();
        assertEquals(2222, adder.add(1234, 988));
    }
}

Tässä tapauksessa yksikötestit, jotka on kirjoitettu ensin, toimivat suunnitteludokumenttina, joka määrittelee halutun ratkaisun muodon ja käyttäytymisen, mutta eivät toteuttajan yksityiskohtia, jotka jätetään ohjelmoijalle. Seuraamalla "tee yksinkertaisinta asiaa, joka mahdollisesti voisi toimia" -harjoitusta, helpoin ratkaisu, joka tekee koepassin, näkyy alla.

interface Adder {
    int add(int a, int b);
}
class AdderImpl implements Adder {
    public int add(int a, int b) {
        return a + b;
    }
}

Suoritettavina määrittelyinä

Yksikkötestien käyttämisellä suunnittelumäärittelyinä on yksi merkittävä etu muihin suunnittelumenetelmiin verrattuna: Suunnitteludokumenttia (itse yksikkötestejä) voidaan itse käyttää toteutuksen tarkistamiseen. Testit eivät läpäise koskaan, ellei kehittäjä toteuta suunnittelun mukaista ratkaisua.

Yksikkötestauksessa ei ole joitain kaaviomääritysten, kuten UML- kaavion, saatavuutta, mutta ne voidaan luoda yksikkötestistä automatisoiduilla työkaluilla. Useimmilla nykyaikaisilla kielillä on ilmaisia ​​työkaluja (yleensä saatavana IDE-tiedostojen laajennuksina ). Ilmaiset työkalut, kuten xUnit- kehykseen perustuvat, ulkoistavat näkymän graafisen renderoinnin toiselle järjestelmälle ihmisravinnoksi.

Sovellukset

Äärimmäinen ohjelmointi

Yksikkötestaus on äärimmäisen ohjelmoinnin kulmakivi , joka perustuu automatisoituun yksikkötestauskehykseen . Tämä automatisoitu yksikkötestauskehys voi olla joko kolmas osapuoli, esim. XUnit , tai luotu kehitysryhmässä.

Äärimmäisessä ohjelmoinnissa käytetään yksikkötestien luomista testiohjattuun kehitykseen . Kehittäjä kirjoittaa yksikötestin, joka paljastaa joko ohjelmistovaatimuksen tai vian. Tämä testi epäonnistuu, koska joko vaatimusta ei ole vielä pantu täytäntöön tai koska se paljastaa tarkoituksella vian olemassa olevassa koodissa. Sitten kehittäjä kirjoittaa yksinkertaisen koodin, jotta testi ja muut testit läpäisevät.

Suurin osa järjestelmän koodista on testattu yksikköä, mutta ei välttämättä kaikkia koodin läpi kulkevia polkuja. Äärimmäinen ohjelmointi edellyttää "testaa kaikki, mikä voi rikkoa" -strategian perinteisen "testaa jokainen toteutuspolku" -menetelmän yli. Tämä saa kehittäjät kehittämään vähemmän testejä kuin perinteiset menetelmät, mutta tämä ei todellakaan ole ongelma, pikemminkin tosiseikkojen uudelleenmuotoilu, koska klassisia menetelmiä on harvoin koskaan noudatettu riittävän järjestelmällisesti, jotta kaikki toteutuspolut olisi testattu perusteellisesti. Äärimmäisessä ohjelmoinnissa tunnustetaan yksinkertaisesti, että testaus on harvoin tyhjentävää (koska se on usein liian kallista ja aikaa vievää ollakseen taloudellisesti kannattava) ja antaa ohjeita rajallisten resurssien tehokkaaseen kohdentamiseen.

Tärkeää on, että testikoodia pidetään ensiluokkaisena projektiartefaktina siinä mielessä, että se pidetään samalla laadulla kuin toteutuskoodi poistamalla kaikki päällekkäisyydet. Kehittäjät julkaisevat yksikön testauskoodin koodivarastoon yhdessä sen testaaman koodin kanssa. Äärimmäisen ohjelmoinnin perusteellinen yksikkötestaus mahdollistaa edellä mainitut edut, kuten yksinkertaisemman ja varmemman koodin kehittämisen ja korjaamisen , yksinkertaistetun koodin integroinnin, tarkan dokumentoinnin ja modulaarisemman suunnittelun. Nämä yksikötestit suoritetaan myös jatkuvasti regressiotestin muodossa .

Yksikkötestaus on kriittinen myös Emergent Design -konseptille . Koska uusi muotoilu riippuu voimakkaasti uudelleenrakentamisesta, yksikkötestit ovat olennainen osa.

Yksikkötestauskehykset

Yksikkötestauskehykset ovat useimmiten kolmannen osapuolen tuotteita, joita ei jaeta osana kääntäjäpakettia. Ne auttavat yksinkertaistamaan yksikkötestausprosessia, koska ne on kehitetty monille kielille .

Yksikkötestaus on yleensä mahdollista suorittaa ilman tietyn kehyksen tukea kirjoittamalla asiakaskoodi, joka harjoittaa testattavia yksiköitä ja käyttää väitteitä , poikkeusten käsittelyä tai muita ohjausvirtausmekanismeja vikailmoituksiin. Yksikkötestaus ilman kehystä on arvokasta siinä mielessä, että yksikkötestauksen käyttöönottoon on este ; vähäisten yksikötestien tekeminen on tuskin parempi kuin ei lainkaan, kun taas kun kehys on paikallaan, yksikkötestien lisääminen on suhteellisen helppoa. Joissakin kehyksissä monet edistyneet yksikötestiominaisuudet puuttuvat tai ne on koodattava käsin.

Kielitason yksikötestaustuki

Jotkut ohjelmointikielet tukevat suoraan yksikön testausta. Heidän kieliopinsa ansiosta yksikkötestit voidaan ilmoittaa suoraan tuomatta kirjastoa (onko kolmas osapuoli vai vakio). Lisäksi yksikkötestien loogiset olosuhteet voidaan ilmaista samassa syntaksissa kuin loogiset lausekkeet, joita käytetään muissa kuin yksikötestikoodeissa, kuten mitä käytetään ifja whilelausekkeet.

Kielet, joissa on sisäänrakennettu yksikön testaustuki, ovat:

Joillakin kielillä, joilla ei ole sisäänrakennettua yksikötestaustukea, on erittäin hyvät yksikötestauskirjastot / -kehykset. Näitä kieliä ovat:

Katso myös

Viitteet

Ulkoiset linkit