Toisinaan meillä - ohjelmoijilla ja / tai asiakkaillamme - on rajalliset resurssit kirjoittaa odotetut suoritteet ja automaattiset testit kyseiselle toimitukselle. Kun sovellus on tarpeeksi pieni, voit leikata kulmia ja ohittaa testit, koska muistat (enimmäkseen) mitä tapahtuu muualla koodissa, kun lisäät ominaisuuden, korjaat virheen tai refaktorin. Emme kuitenkaan aina toimi pienten sovellusten kanssa, ja ne yleensä kasvavat ja monimutkaistuvat ajan myötä. Tämä tekee manuaalisen testauksen vaikeaksi ja erittäin ärsyttäväksi.
Viimeisissä projekteissani pakotettiin työskentelemään ilman automaattista testausta ja rehellisesti, oli kiusallista saada asiakas lähettämään minulle sähköpostia koodin painamisen jälkeen sanomaan, että sovellus rikkoi paikoissa, joissa en ollut edes koskenut koodiin.
Joten tapauksissa, joissa asiakkaallani ei ollut budjettia tai aikomusta lisätä automaattista testikehystä, aloin testata koko verkkosivuston perustoimintoja lähettämällä HTTP-pyynnön jokaiselle sivulle, jäsentämällä vastauksen otsikot ja etsimällä 200 vastaus. Kuulostaa yksinkertaiselta ja yksinkertaiselta, mutta voit tehdä paljon varmuuden takaamiseksi tarvitsematta itse kirjoittaa mitään testejä, yksiköitä, toiminnallisia tai integraatioita.
Verkkokehityksessä automaattiset testit koostuvat kolmesta päätyypistä: yksikkötestit, toiminnalliset testit ja integraatiotestit. Yhdistämme usein yksikötestit toiminnallisiin ja integraatiotesteihin varmistaaksemme, että kaikki toimii sujuvasti kokonaisuutena. Kun nämä testit suoritetaan yhtenäisesti tai peräkkäin (mieluiten yhdellä komennolla tai napsautuksella), alamme kutsua niitä automaattisiksi testeiksi, yksiköinä tai ei.
Suurimmaksi osaksi näiden testien tarkoituksena (ainakin verkkokehityksessä) on varmistaa, että kaikki sovellussivut renderoidaan ongelmitta, ilman vakavia (sovelluksen pysäyttämistä) virheitä tai virheitä.
Yksikkötestaus on ohjelmistokehitysprosessi, jossa pienimmätkin koodin osat - yksiköt - testataan itsenäisesti oikein. Tässä on esimerkki Ruby:
test “should return active users” do active_user = create(:user, active: true) non_active_user = create(:user, active: false) result = User.active assert_equal result, [active_user] end
Toiminnallinen testaus on tekniikka, jota käytetään järjestelmän tai ohjelmiston ominaisuuksien ja toiminnallisuuden tarkistamiseen ja joka on suunniteltu kattamaan kaikki käyttäjän vuorovaikutusskenaariot, mukaan lukien vikareitit ja rajatapaukset.
Huomaa: kaikki esimerkit ovat Ruby-kirjassa.
test 'should get index' do get :index assert_response :success assert_not_nil assigns(:object) end
Kun moduulit on testattu yksikköä, ne integroidaan yksi kerrallaan peräkkäin, jotta voidaan tarkistaa yhdistelmäkäyttäytyminen ja varmistaa, että vaatimukset on pantu täytäntöön oikein.
test 'login and browse site' do # login via https https! get '/login' assert_response :success post_via_redirect '/login', username: users(:david).username, password: users(:david).password assert_equal '/welcome', path assert_equal 'Welcome david!', flash[:notice] https!(false) get '/articles/all' assert_response :success assert assigns(:articles) end
Testaus on yleisesti hyväksytty teollisuudessa, ja se on järkevää; hyvien testien avulla voit:
Voisin jatkaa siitä, kuinka mahtavat testit ovat ja kuinka ne muuttivat maailmaa ja yada yada yada, mutta ymmärrät. Käsitteellisesti testit ovat mahtavia.
Liittyvät: Yksikkötestit, kuinka kirjoittaa testattava koodi ja miksi sillä on merkitystäVaikka kaikilla kolmella testaustyypillä on ansioita, niitä ei kirjoiteta useimmissa projekteissa. Miksi? No, anna minun hajottaa se:
Jokaisella on määräajat, ja uusien testien kirjoittaminen voi olla tapa saavuttaa yksi. Hakemuksen kirjoittaminen voi kestää puolitoista (tai enemmän) aikaa ja sen testit. Jotkut teistä eivät ole samaa mieltä tästä vedoten lopulta säästettyyn aikaan, mutta en usko, että näin on, ja selitän miksi kohdassa 'mielipide-ero'.
Usein asiakas ei oikein ymmärrä, mikä testaus on tai miksi sillä on arvoa sovellukselle. Asiakkaat ovat yleensä kiinnostuneempia tuotteiden nopeasta toimituksesta ja pitävät siksi ohjelmallista testausta haitallisena.
Tai voi olla niin yksinkertaista, että asiakkaalla ei ole budjettia maksaa näiden testien toteuttamiseen tarvittavasta lisäajasta.
Todellisessa maailmassa on huomattava joukko kehittäjiä, jotka eivät tiedä testausta. Jokaisessa konferenssissa, tapaamisissa, konsertissa (jopa unelmissani) tapaan kehittäjiä, jotka eivät osaa kirjoittaa testejä, eivät tiedä mitä testata, eivät osaa asentaa kehystä testaukseen jne. päällä. Testausta ei opeta tarkalleen kouluissa, ja niiden luominen / hankkiminen voi olla hankalaa. Joten kyllä, maahantulolle on selvä este.
Testien kirjoittaminen voi olla ylivoimainen sekä uusille että kokeneille ohjelmoijille, jopa niille maailmanmuuttaja nerotyypeille, ja huipuksi testien kirjoittaminen ei ole jännittävää. Voi ajatella: 'Miksi minun pitäisi harjoittaa jännittävää kiireistä työtä, kun voisin toteuttaa tärkeän ominaisuuden tuloksilla, jotka vaikuttavat asiakkaaseni?' Se on vaikea argumentti.
Viimeinen mutta ei vähäisin, testejä on vaikea kirjoittaa ja tietojenkäsittelytieteen opiskelijoita ei ole koulutettu siihen.
Voi, ja uudelleenkäsittely yksikkötesteillä ei ole hauskaa.
Mielestäni yksikötestauksella on järkeä algoritmiselle logiikalle, mutta ei niin paljon elävän koodin koordinoinnille.
Ihmiset väittävät, että vaikka investoisit ylimääräistä aikaa etukäteen testien kirjoittamiseen, se säästää tunteja myöhemmin virheenkorjauksessa tai koodin vaihdossa. Pyydän erimielisyyttä ja tarjoan yhden kysymyksen: Onko koodisi staattinen vai muuttumassa?
Suurimmalle osalle meistä se muuttuu jatkuvasti. Jos kirjoitat onnistunutta ohjelmistoa, lisäät aina ominaisuuksia, vaihdat olemassa olevia, poistat niitä, syövät niitä ja mitä, ja näiden muutosten huomioon ottamiseksi sinun on jatkuvasti muutettava testejäsi, ja testien vaihtaminen vie aikaa.
Kukaan ei väitä, että minkäänlaisen testauksen puuttuminen on pahin mahdollinen tapaus. Kun olet tehnyt muutoksia koodiin, sinun on vahvistettava, että se todella toimii. Monet ohjelmoijat yrittävät testata perusasiat manuaalisesti: Onko sivun renderöinti selaimessa? Lähetetäänkö lomake? Näkyykö oikea sisältö? Ja niin edelleen, mutta mielestäni tämä on barbaarista, tehotonta ja työvoimavaltaista.
Verkkosovelluksen testauksen tarkoituksena on olla manuaalinen tai automaattinen vahvistus siitä, että mikä tahansa annettu sivu renderöidään käyttäjän selaimessa ilman kohtalokkaita virheitä ja että se näyttää sen sisällön oikein. Yksi tapa (ja useimmissa tapauksissa helpoin tapa) saavuttaa tämä on lähettää HTTP-pyynnöt sovelluksen päätepisteisiin ja jäsentää vastaus. Vastauskoodi kertoo, toimitettiinko sivu onnistuneesti. Sisällön testaaminen on helppoa jäsentämällä HTTP-pyynnön vastausrunko ja etsimällä tiettyjä tekstimerkkijono-osumia. Voit myös olla yksi vaihe harrastaja ja käyttää verkon kaavinta-kirjastoja, kuten nokogiri .
Jos jotkin päätepisteet edellyttävät käyttäjän kirjautumista, voit käyttää kirjastoja, jotka on suunniteltu vuorovaikutusten automatisointiin (ihanteellinen integrointitestien tekemisessä), kuten koneellistaa kirjaudu sisään tai napsauta tiettyjä linkkejä. Todellakin, automatisoidun testauksen suuressa kuvassa tämä näyttää paljon integraatiolta tai toiminnalliselta testaukselta (riippuen siitä, miten käytät niitä), mutta se on paljon nopeampi kirjoittaa ja se voidaan sisällyttää olemassa olevaan projektiin tai lisätä uuteen , vähemmän vaivaa kuin koko testauskehyksen luominen. Naulankantaan!
Liittyvät: Palkkaa 3% freelance QA -insinööreistä.Reunatapaukset aiheuttavat toisen ongelman käsiteltäessä suuria tietokantoja, joilla on laaja valikoima arvoja; sen testaaminen, toimiiko sovelluksemme sujuvasti kaikissa odotettavissa olevissa aineistoissa, voi olla pelottavaa.
Yksi tapa edetä on ennakoida kaikki reunatapaukset (mikä ei ole vain vaikeaa, se on usein mahdotonta) ja kirjoittaa testi jokaiselle. Tästä voi helposti tulla satoja koodiriviä (kuvittele kauhua) ja hankala ylläpitää. Silti HTTP-pyyntöjen ja vain yhden koodirivin avulla voit testata tällaisia reunatapauksia suoraan tuotannosta saatavista tiedoista, jotka on ladattu paikallisesti kehityskoneellasi tai välityspalvelimelta.
Nyt tämä testaustekniikka ei tietenkään ole hopeamalli ja siinä on paljon puutteita, samat kuin missä tahansa muussa menetelmässä, mutta mielestäni tämäntyyppiset testit on nopeampi ja helpompi kirjoittaa ja muokata.
Koska olemme jo todenneet, että koodin kirjoittaminen ilman minkäänlaisia mukana olevia testejä ei ole hyvä idea, koko sovellukseni perustesti on lähettää HTTP-pyyntöjä kaikille sen sivuille paikallisesti ja jäsentää vastauksen otsikot 200
(tai haluttu) koodi.
Esimerkiksi, jos kirjoittaisimme yllä olevat testit (jotka etsivät tiettyä sisältöä ja kohtalokasta virhettä) HTTP-pyynnöllä (Ruby-muodossa), se olisi jotain tällaista:
# testing for fatal error http_code = `curl -X #{route[:method]} -s -o /dev/null -w '%{http_code}' #{Rails.application.routes.url_helpers.articles_url(host: 'localhost', port: 3000) }` if http_code !~ /200/ return “articles_url returned with #{http_code} http code.” end # testing for content active_user = create(:user, name: “user1”, active: true) non_active_user = create(:user, name: “user2”, active: false) content = `curl #{Rails.application.routes.url_helpers.active_user_url(host: 'localhost', port: 3000) }` if content !~ /#{active_user.name}/ return “Content mismatch active user #{active_user.name} not found in text body” #You can customise message to your liking end if content =~ /#{non_active_user.name}/ return “Content mismatch non active user #{active_user.name} found in text body” #You can customise message to your liking end
Rivi curl -X #{route[:method]} -s -o /dev/null -w '%{http_code}' #{Rails.application.routes.url_helpers.articles_url(host: 'localhost', port: 3000) }
kattaa paljon testitapauksia; kaikki menetelmät, jotka aiheuttavat virheen artikkelin sivulla, löytyvät tästä, joten se kattaa käytännössä satoja koodirivejä yhdessä testissä.
Toista osaa, joka sieppaa sisältövirheen nimenomaan, voidaan käyttää useita kertoja sivun sisällön tarkistamiseen. (Monimutkaisempia pyyntöjä voidaan käsitellä mechanize
-sovelluksen avulla, mutta tämä ei kuulu tämän blogin piiriin.)
Nyt, jos haluat testata, toimiiko tietty sivu suurilla, vaihtelevilla tietokannan arvoilla (esimerkiksi artikkelisivumallisi toimii kaikkien tuotantotietokannan artikkeleiden kanssa), voit tehdä seuraavaa:
ids = Article.all.select { |post| `curl -s -o /dev/null -w “%{http_code}” #{Rails.application.routes.url_helpers.article_url(post, host: 'localhost', port: 3000) }`.to_i != 200).map(&:id) return ids
Tämä palauttaa joukon tunnuksia kaikista tietokannan artikkeleista, joita ei ole renderoitu, joten voit nyt siirtyä manuaalisesti tietylle artikkelisivulle ja tarkistaa ongelman.
Ymmärrän nyt, että tämä testaustapa ei välttämättä toimi tietyissä tapauksissa, kuten erillisen komentosarjan testaaminen tai sähköpostin lähettäminen, ja se on kiistatta hitaampaa kuin yksikkötestit, koska soitamme suoria kutsuja jokaiselle testille, mutta kun sinulla ei voi olla yksikötestejä, toiminnallisia testejä tai molempia, tämä on parempi kuin ei mitään.
Kuinka jatkat näiden testien jäsentämistä? Pienillä, monimutkaisilla projekteilla voit kirjoittaa kaikki testisi yhteen tiedostoon ja suorittaa tiedoston joka kerta ennen muutosten tekemistä, mutta useimmat projektit vaativat testisarjan.
Kirjoitan yleensä kaksi tai kolme testiä per päätepiste, testattavastani riippuen. Voit myös kokeilla yksittäisen sisällön testaamista (samanlainen kuin yksikötestaus), mutta mielestäni se olisi turhaa ja hidasta, koska soitat HTTP-puhelun jokaiselle yksikölle. Mutta toisaalta ne ovat puhtaampia ja helposti ymmärrettäviä.
Suosittelen, että laitat testisi tavalliseen testikansioon siten, että jokaisella pääpisteellä on oma tiedosto (esimerkiksi Railsissa kullakin mallilla / ohjaimella olisi yksi tiedosto), ja tämä tiedosto voidaan jakaa kolmeen osaan sen mukaan, mitä me testaavat. Minulla on usein vähintään kolme testiä:
Tarkista, että sivu palaa ilman kohtalokkaita virheitä.
Huomaa, miten tein luettelon kaikista päätepisteistä Post
ja toistettiin sen yli tarkistaaksesi, että jokainen sivu on renderoitu virheettömästi. Olettaen, että kaikki meni hyvin ja kaikki sivut renderoitiin, näet terminaalissa jotain tällaista: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of failed url(s) -- []
Jos jotakin sivua ei renderöidä, näet jotain tällaista (tässä esimerkissä posts/index page
: lla on virhe eikä sitä näin ollen renderöidä): ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of failed url(s) -- [{:url=>”posts_url”, :params=>[], :method=>”GET”, :http_code=>”500”}]
Varmista, että kaikki odotettu sisältö on olemassa:
Jos kaikki odotettu sisältö löytyy sivulta, tulos näyttää tältä (tässä esimerkissä varmistamme, että posts/:id
on postin otsikko, kuvaus ja tila): ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of content(s) not found on Post#show page with post id: 1 -- []
Jos sivulta ei löydy odotettua sisältöä (tässä oletamme sivun näyttävän viestin tilan - Aktiivinen, jos viesti on aktiivinen, Ei käytössä, jos viesti on poistettu käytöstä), tulos näyttää tältä: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of content(s) not found on Post#show page with post id: 1 -- [“Active”]
Tarkista, että sivu hahmonnetaan kaikissa tietojoukoissa (jos sellaisia on):
Jos kaikki sivut renderoidaan ilman virheitä, saamme tyhjän luettelon: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of post(s) with error in rendering -- []
Jos joidenkin tietueiden sisällössä on ongelmia renderoinnissa (tässä esimerkissä sivut, joiden tunnus on 2 ja 5, antavat virheen), tulos näyttää tältä: ➜ sample_app git:(master) ✗ ruby test/http_request/post_test.rb List of post(s) with error on rendering -- [2,5]
Jos haluat käpertyä yllä olevan esittelykoodin kanssa, tässä on github-projektini .
HTTP-pyynnön testaus voi olla paras vaihtoehto, jos:
Perinteinen testaus on ihanteellinen, kun:
Kiitos artikkelin lukemisesta; Sinulla pitäisi nyt olla menetelmä testaamiseen, jonka voit oletusarvoisesti käyttää. Voit luottaa siihen, kun painat aikaa.
Liittyvät: