Se on vain tosiasia, kuten koodin kasvaa lopulta sinun täytyy aloittaa lisäämällä pilkkaa sinun test suite. Söpönä pikku kakkosluokan projektina aloittanut puhuu nyt ulkoisille palveluille, eikä sitä voi enää testata mukavasti.
siksi Python-alukset unittest.mock
, voimakas osa standardin kirjasto stubbing riippuvuudet ja pilkaten sivuvaikutuksia.
unittest.mock
ei kuitenkaan ole erityisen intuitiivinen.,
– olen löytänyt itseni monta kertaa mietin, miksi minun go-resepti ei toimi tietyssä tapauksessa, joten olen koonnut tämän cheatsheet auttaa itseäni ja muita pilkkaa toimi nopeasti.
koodiesimerkit löytyvät artikkelin GitHub-arkistosta. Käytän Python 3.6, jos käytät 3.2 tai alla sinun täytyy käyttää mock
PyPI paketti.,
esimerkit on kirjoitettu käyttäen unittest.TestCase
luokat yksinkertaisuus suorittamista niitä ilman riippuvuuksia, mutta voit kirjoittaa niitä toimintoja käyttämällä pytest
lähes suoraan,unittest.mock
toimii hienosti. Jos olet pytest
käyttäjä vaikka en rohkaista voit vilkaista erinomainen pytest-mock
kirjasto.
centerpoint, että unittest.mock
module on, tietenkin, Mock
luokka., Tärkein ominaisuus Mock
esine on, että se palaa taas Mock
esimerkiksi, kun:
- pääsy yksi sen ominaisuuksia
- soittamalla esine itse
Tämä on oletusarvo käyttäytymistä, mutta se voidaan ohittaa eri tavoin. Esimerkiksi voit määrittää arvon määrite Mock
esittäjä:
- Liitä se suoraan, aivan kuten tekisit minkä tahansa Python objektin.,
- Käytä
configure_mock
menetelmällä, esimerkiksi. - Tai siirtää avainsanan argumentteja
Mock
luokan luomiseen.
ohittaa puhelut pilkata sinun täytyy määrittää sen return_value
omaisuutta, saatavana myös avainsanan argumentti Mock
alustajan., Mock
palaa aina sama arvo kaikki puhelut, tämä, jälleen, voidaan määrittää myös käyttämällä side_effect
ominaisuus:
- jos haluat palauttaa eri arvoja, jokaisen puhelun, voit määrittää iterable että
side_effect
. - Jos haluat nostaa poikkeus, kun soittaa Mock voit yksinkertaisesti määrittää ottamatta objekti
side_effect
.,
kaikki nämä työkalut, voimme nyt luoda tyngät lähinnä tahansa Python objektin, joka toimii suuri tuotantopanosten meidän järjestelmä. Mutta entä tuotokset?
Jos teet CLI-ohjelma ladata koko Internet, et luultavasti halua ladata koko Internet-kunkin testin. Sen sijaan riittäisi väittämään, että requests.download_internet
(ei todellinen menetelmä) kutsuttiin asianmukaisesti. Mock
antaa siihen käteviä menetelmiä.,
Huomautus tässä esimerkissä assert_called_once
ei, tämä esittelee toinen keskeinen näkökohta Mock
esineitä, ne tallentaa kaikki interaktio heidän kanssaan ja voit sitten tarkastaa näiden vuorovaikutusta.
esimerkiksi et voi käyttää call_count
hakea puheluiden Mock
ja käyttää call_args
tai call_args_list
tarkastaa argumentteja viimeinen tai kaikki puhelut vastaavasti.,
Jos tämä on hankalaa, voit milloin tahansa käyttää reset_mock
tapa tyhjentää tallennetut interaktio, huomaa kokoonpano ei nollata, vain vuorovaikutusta.
Lopuksi, sallikaa minun esitellä MagicMock
, alaluokka Mock
, joka toteuttaa default magic tai dunder menetelmiä. Tämä tekee MagicMock
ihanteellinen mock-luokan käyttäytyminen, joka on, miksi se on oletuksena luokassa, kun kauneuspilkku.,
olemme nyt valmiita aloittamaan irvailun ja eristämään yksikön testeissä. Tässä muutamia reseptejä pitää mielessä:
Laastari tuonti
tärkein tapa käyttää unittest.mock
on laastari tuonti moduuli testattavan käyttäen patch
toiminto.
patch
siepata import
lausunnot tunnistaa merkkijono (siitä lisää myöhemmin), ja palauttaa Mock
esimerkiksi voit määrittää valmiiksi käyttämällä tekniikoita olemme keskustelleet edellä.,
Kuvittele, että haluamme testata tämän hyvin yksinkertainen tehtävä:
Huomaa, että olemme tuominen os
ja soittaa getcwd
saada nykyisen työhakemiston. Emme halua kutsua sitä testeissämme, vaikka se ei ole tärkeää koodillemme ja palautusarvo voi vaihdella ympäristöjen välillä.
Kuten edellä mainittiin, meidän täytyy toimittaa patch
merkkijono, joka edustaa meitä erityiset tuontia., Emme halua toimittaa vain os.getcwd
sillä se ei yhdistä kaikki moduulit, sen sijaan haluamme toimittaa moduulin alla testi on import
ja os
eli work.os
. Kun moduuli on tuotu patch
toimii sen taika ja palauttaa Mock
sijaan.,
Vaihtoehtoisesti, voimme käyttää sisustusarkkitehti versio patch
, huomaa tämä, kun testi on ylimääräinen parametri: mocked_os
jossa Mock
ruiskutetaan testi.,
patch
toimittaa avainsanan argumentteja Mock
luokan, joten voit määrittää return_value
emme yksinkertaisesti lisää se yksi:
Pilkaten luokat
– Se on melko yleinen patch luokat täysin tai osittain., Helper
"db"
Worker
palauttaa odotettavissa polku toimittamien Helper
jotta testi Worker
täydellisessä eristyksessä meidän täytyy paikata koko Helper
class:
Huomautus double return_value
esimerkissä, yksinkertaisesti käyttämällä MockHelper.get_path.return_value
ei toimisi sillä koodi me kutsumme get_path
esimerkiksi, ei luokan itse.,
ketjutus syntaksi on hieman sekava, mutta muista MagicMock
palaa taas MagicMock
puhelut __init__
. Täällä olemme konfigurointi mitään fake Helper
tapauksissa luoma MockHelper
palaa, mitä me odotamme puhelut get_path
mikä on ainoa tapa, me välitämme meidän testi.,
Luokan speccing
seuraus joustavuus Mock
on, että kun olemme pilkkasivat luokan Python ei nosta AttributeError
koska se yksinkertaisesti palaa uusia esiintymiä MagicMock
periaatteessa kaikki. Tämä on yleensä hyvä asia, mutta voi johtaa joidenkin sekava käytös ja mahdollisesti vikoja. Esimerkiksi kirjoittaa seuraavaa testiä,
hiljaa kulkea ilman varoitusta puuttuu kokonaan typo assrt_called_once
.,
Lisäksi, jos olimme nimetä Helper.get_path
ja Helper.get_folder
, mutta unohda päivittää soittaa Worker
meidän testit on vielä läpäistävä:
Onneksi Mock
mukana tulee työkalu estää näitä virheitä, speccing.
Yksinkertaisesti sanottuna, se ennakkoasetukset pilkkaa vastata vain menetelmiin, jotka todella ovat olemassa spec-luokassa., On olemassa useita tapoja määrittää, silmälasit, mutta helpoin on yksinkertaisesti pass autospec=True
ja patch
puhelu, joka määrittää Mock
käyttäytyä kuin esine on pilkattu, nostaa poikkeuksia varten puuttuu ominaisuuksia ja virheelliset allekirjoitukset tarvittaessa., Esimerkiksi:
Osittainen luokan pilkkaa
Jos olet vähemmän taipuvaisia testaus täydellinen eristäminen voit myös osittain paikata luokan käyttäen patch.object
:
Täältä patch.object
on antaa meille mahdollisuuden määrittää pilkkasivat versio get_path
vain, jättäen loput käyttäytyminen koskemattomana., Tietenkin tämä tarkoittaa, että testi ei ole enää mitä ehdottomasti harkita yksikkötestin, mutta voit olla ok, että.
Pilkaten rakennettu-in toimintoja, ja ympäristömuuttujat
edellisissä esimerkeissä olemme laiminlyöty testata erityisesti yksi seikka, yksinkertainen luokka, print
puhelu. Jos yhteydessä hakemuksesi tämä on tärkeää, kuten CLI-komento, esimerkiksi, meidän täytyy tehdä väitteitä vastaan tätä kutsua.,
print
– on, tietenkin sisäänrakennettu toiminto Python, mikä tarkoittaa, että meidän ei tarvitse tuoda se meidän moduuli, joka on vastoin sitä, mitä olemme edellä paikkauksesta tuonti., Silti kuvitella, että meillä oli tämä hieman monimutkaisempi versio meidän tehtävä:
voidaan kirjoittaa testi, kuten seuraavat:
Huom muutamia asioita:
- emme voi pilkata
print
kanssa mitään ongelmaa ja väittää, että siellä oli puhelun jälkeen ”laastari tuo” sääntö. Tämä oli kuitenkin muutos, joka otettiin käyttöön 3.,5, aiemmin sinun piti lisätäcreate=True
japatch
puhelu signaaliunittest.mock
luodaMock
vaikka ei tuo vastaa tunniste. - käytämme
patch.dict
pistää väliaikainen ympäristö muuttujaos.environ
tämä on laajennettavissa muihin sanakirja haluamme pilkata., - olemme pesii useita
patch
context manager puhelut, mutta vain käyttämälläas
ensimmäinen, koska se on yksi meidän täytyy soittaaassert_called_once_with
.,
Jos et ole ihastunut pesintä yhteydessä johtajien voit myös kirjoittaa patch
puhelut sisustusarkkitehti muodossa:
Huomaa kuitenkin, jotta argumentit testi sopii pinoaminen järjestyksessä, sisustussuunnittelijan, ja myös, että patch.dict
ei pistä argumentti.,tämä on hyvin yleinen skenaario:
Voit, tietenkin, lisää todellinen valaisin-tiedoston, mutta todellisessa maailmassa tapauksissa se voisi olla vaihtoehto, sen sijaan voimme pilkata yhteydessä manager on lähtö olla StringIO
kohde:
Ei ole mitään erityistä täällä paitsi maaginen __enter__
menetelmä, meidän täytyy vain muistaa taustalla oleva mekaniikka yhteydessä johtajat ja jotkut näppärä käyttää meidän luotettava MagicMock
.,
Pilkkaluokan attribuutit
on monia tapoja saavuttaa tämä, mutta jotkut ovat typerämpiä todisteita siitä, että toiset. Oletetaan, että olet kirjoittanut seuraavan koodin:
Voit testata koodia ilman mitään pilkkaa kahdella tavalla:
- Jos koodi testattavan käyttää määritteen kautta
self.ATTRIBUTE
, joka tapauksessa tässä esimerkissä, voit yksinkertaisesti aseta attribuutin suoraan esimerkiksi. Tämä on melko turvallista, koska muutos rajoittuu tähän yksittäiseen tapaukseen., - Vaihtoehtoisesti voit myös asettaa ominaisuuden tuontiluokassa testissä ennen instanssin luomista. Tämä kuitenkin muuttaa luokan ominaisuus olet tuonut testiin, joka voi vaikuttaa seuraaviin testeihin, joten sinun täytyy muistaa nollata se.
suurin haittapuoli tämän non-Mock lähestymistapoja on, että jos et missään vaiheessa nimetä ominaisuus testeistä epäonnistuu, ja virhe ei suoraan mainita, että tämä nimeäminen epäsuhta.,
ratkaista, että voimme käyttää patch.object
tuodut luokan, joka valittaa, jos luokassa ei ole määritelty ominaisuus.
Tässä ovat jotkut testit käyttäen kunkin tekniikka:
Pilkaten luokan auttajia
seuraava esimerkki on juuri monia ongelmia monkeypatching käyttää Pilkata. Se näkyy yleensä kypsemmillä koodebaaseilla, jotka alkavat hyödyntää kehyksiä ja auttajia luokkamäärittelyssä., Esimerkiksi, kuvitella, että tämä hypoteettinen Field
helper class:
Sen tarkoitus on paketoida ja parantaa määrite toiseen luokkaan, melko kuvio yleisesti voi nähdä ORMs tai muodossa kirjastot. Älä huoli itseäsi liian paljon yksityiskohtia se vain huomaa, että on olemassa type
ja default
arvo läpäissyt.,
Nyt ottaa toinen näyte tuotanto koodi:
Tämä luokka käyttää Field
luokan määrittelemällä sen country
ominaisuus kuin yksi, jonka tyyppi on str
ja default
ensimmäinen elementti COUNTRIES
vakio. Testin logiikkana on, että maasta riippuen alennusta sovelletaan.,
joista voimme kirjoittaa seuraava testi:
Mutta se EI kulje.,
käydään läpi testi:
- Ensin se laastaria oletuksena maiden
pricer
lista yhden merkinnänGB
, - Tämä pitäisi tehdä
CountryPricer.country
attribuutti, default, että merkintä koska se määritelmä sisältäädefault=COUNTRIES
, - Se sitten instanciates
CountryPricer
ja pyytää alennettuun hintaanGB
!
So what ’ s going on?,
perussyy tähän on Python käyttäytymistä tuonnin aikana, parhaiten kuvata Luciano Ramalho on erinomainen Sujuva Python 21 luku:
luokat, tarina on erilainen: milloin tuo aika, tulkki suorittaa kehon jokaisen luokan, jopa kehon luokat, sisäkkäisiä muissa luokissa. Luokkarungon toteutus tarkoittaa sitä, että luokan attribuutit ja menetelmät määritellään, ja sitten itse luokkaobjekti rakennetaan.,
Soveltamalla tätä meidän esimerkki:
-
country
attribuutinField
oikeusasteen tuomioistuin on rakennettu ennen testiä on juoksi tuo aika, - Python lukee kehon luokan kulkee
COUNTRIES
, joka on määritelty tässä vaiheessaField
esimerkiksi - Meidän testi koodi toimii, mutta se on liian myöhäistä paikata
COUNTRIES
ja saada oikea väite.,
edellä kuvaus voit kokeilla viivästyttää tuonti moduuli, kunnes sisällä testejä, jotain:
Tämä, kuitenkin, ei ole vielä ohi kuten mock.patch
tuo moduuli ja sitten monkeypatch se, mikä samassa tilanteessa kuin ennen.,
Voit kiertää tämän, meidän täytyy omaksua valtion CountryPricer
luokka aikaan testin ja patch default
jo alustettu Field
esimerkiksi:
Tämä ratkaisu ei ole ihanteellinen, koska se vaatii tietoa sisäosat Field
joka ei välttämättä ole tai halua käyttää, jos käytät ulkoista kirjastosta, mutta se toimii tässä tosin yksinkertaistettu tapaus.,
tämä maahantuonnin aikanumero on yksi suurimmista ongelmista, joita olen kohdannut unittest.mock
. Sinun täytyy muistaa, kun käytät sitä, että tuonnin aikakoodi huipputasolla moduulit suoritetaan, mukaan lukien luokan elimet.
Jos logiikka olet testaus on riippuvainen tästä mitään logiikkaa, voit joutua uudelleen, miten käytät patch
vastaavasti.,
niputtamiseen
Tämä käyttöönotto ja cheatsheet pitäisi saada sinut pilkaten unittest.mock
, mutta kehotan teitä lue ohjeet huolellisesti, siellä on paljon enemmän mielenkiintoisia temppuja oppia.
Se on syytä mainita, että on olemassa vaihtoehtoja unittest.mock
erityisesti Alex Gaynor on pretend
kirjasto yhdessä pytest
’s monkeypatch
ottelua. Kuten Alex huomauttaa, käyttämällä näitä kahta kirjastoa voit tehdä pilkkaamisesta tiukempaa ja ennustettavampaa., Ehdottomasti lähestymistapa kannattaa tutkia, mutta ulkopuolella tämän artikkelin.
unittest.mock
on tällä hetkellä standardi pilkaten Python ja löydät sen lähes joka codebase. Ottaa vankka ymmärrys siitä auttaa sinua kirjoittamaan parempia testejä nopeammin.