edge
Daugiau informacijos rubyonrails.org: Daugiau apie Ruby on Rails

Rails aplikacijų testavimas

Šiame vadove aptariamos įdiegtos mechanizmai „Rails“ aplikacijų testavimui.

Po šio vadovo perskaitymo žinosite:

Chapters

  1. Kodėl rašyti testus savo „Rails“ aplikacijoms?
  2. Įvadas į testavimą
  3. Lygiagretus testavimas
  4. Testinė duomenų bazė
  5. Modelio testavimas
  6. Sistemos testavimas
  7. Integracinis testavimas
  8. Funkciniai testai jūsų valdikliams
  9. Maršrutų testavimas
  10. Peržiūrėti testavimą
  11. Testavimo pagalbininkai(fixed)
  12. Pašto siuntėjų testavimas
  13. Darbo testavimas
  14. Action Cable testavimas
  15. Eager Loading testavimas
  16. Papildomi testavimo ištekliai

1 Kodėl rašyti testus savo „Rails“ aplikacijoms?

„Rails“ labai supaprastina testų rašymą. Jis pradeda generuoti testų kodą, kai kuriate savo modelius ir valdiklius.

Paleidę savo „Rails“ testus galite užtikrinti, kad jūsų kodas atitinka norimą funkcionalumą net po didelių kodų pertvarkymų.

„Rails“ testai taip pat gali simuliuoti naršyklės užklausas, todėl galite testuoti savo aplikacijos atsaką, neturėdami testuoti per naršyklę.

2 Įvadas į testavimą

Testavimo palaikymas buvo įtrauktas į „Rails“ nuo pat pradžių. Tai nebuvo „o! pridėkime palaikymą testams, nes jie nauji ir stilingi“ epifanija.

2.1 „Rails“ pasiruošęs testavimui nuo pat pradžių

„Rails“ jums sukuria test katalogą, kai tik sukuriate „Rails“ projektą naudodami rails new application_name. Jei išvardinsite šio katalogo turinį, pamatysite:

$ ls -F test
application_system_test_case.rb  controllers/                     helpers/                         mailers/                         system/
channels/                        fixtures/                        integration/                     models/                          test_helper.rb

helpers, mailers ir models katalogai skirti laikyti testus, atitinkamai, rodinių pagalbininkams, pašto siuntėjams ir modeliams. channels katalogas skirtas laikyti testus, skirtus „Action Cable“ ryšiui ir kanalams. controllers katalogas skirtas laikyti testus, skirtus valdikliams, maršrutams ir rodiniams. integration katalogas skirtas laikyti testus, skirtus sąveikai tarp valdiklių.

Sistemos testų katalogas laiko sistemos testus, kurie naudojami visapusiškam naršyklės testavimui. Sistemos testai leidžia jums testuoti savo aplikaciją taip, kaip ją patiria jūsų vartotojai, ir padeda jums testuoti savo „JavaScript“. Sistemos testai paveldi iš „Capybara“ ir atlieka naršyklės testus jūsų aplikacijai.

Testiniai duomenys yra būdas organizuoti testavimo duomenis; jie yra fixtures kataloge.

Kai pirmą kartą generuojamas susijęs testas, taip pat bus sukurtas jobs katalogas.

test_helper.rb failas laiko numatytąją konfigūraciją jūsų testams.

application_system_test_case.rb laiko numatytąją konfigūraciją jūsų sistemos testams.

2.2 Testavimo aplinka

Pagal numatytuosius nustatymus kiekviena „Rails“ aplikacija turi tris aplinkas: vystymo, testavimo ir produkto.

Kiekvienos aplinkos konfigūraciją galima keisti panašiai. Šiuo atveju galime keisti mūsų testavimo aplinką, keisdami parinktis, esančias config/environments/test.rb.

PASTABA: Jūsų testai vykdomi pagal RAILS_ENV=test.

2.3 „Rails“ susitinka su „Minitest“

Jeigu prisimenate, mes naudojome bin/rails generate model komandą Pradedant su „Rails“ vadove. Mes sukūrėme pirmąjį modelį, ir tarp kitų dalykų jis sukūrė testo šablonus test kataloge:

$ bin/rails generate model article title:string body:text
...
create  app/models/article.rb
create  test/models/article_test.rb
create  test/fixtures/articles.yml
...

Numatytasis testo šablonas test/models/article_test.rb atrodo taip:

require "test_helper"

class ArticleTest < ActiveSupport::TestCase
  # test "the truth" do
  #   assert true
  # end
end

Eilutė po eilutės šio failo nagrinėjimas padės jums susiorientuoti „Rails“ testavimo kodo ir terminologijos atžvilgiu.

require "test_helper"

Įtraukdami šį failą, test_helper.rb, įkeliamas numatytasis konfigūravimas, skirtas paleisti mūsų testus. Mes įtrauksime šį failą į visus rašomus testus, todėl visiems mūsų testams bus prieinami šiame faile pridėti metodai.

class ArticleTest < ActiveSupport::TestCase

ArticleTest klasė apibrėžia testo atvejį, nes ji paveldi iš ActiveSupport::TestCase. ArticleTest taigi turi visus iš ActiveSupport::TestCase paveldėtus metodus. Vėliau šiame vadove pamatysime keletą iš jų.

Bet koks metodas, apibrėžtas klasėje, paveldėtoje iš Minitest::Test (kuri yra ActiveSupport::TestCase superklasė) ir prasidedantis su test_, paprasčiausiai vadinamas testu. Taigi, metodai, apibrėžti kaip test_password ir test_valid_password, yra teisėti testo pavadinimai ir yra automatiškai vykdomi, kai vykdomas testo atvejis. Rails taip pat prideda test metodą, kuris priima testo pavadinimą ir bloką. Jis generuoja įprastinį Minitest::Unit testą, kurio metodų pavadinimai pradeda nuo test_. Taigi, jums nereikia rūpintis metodų pavadinimais, ir galite parašyti kažką tokio:

test "tiesa" do
  assert true
end

Tai apytiksliai tas pats, kas rašyti tai:

def test_tiesa
  assert true
end

Nors vis tiek galite naudoti įprastus metodų apibrėžimus, naudojant test makro leidžia rašyti aiškesnį testo pavadinimą.

PASTABA: Metodo pavadinimas generuojamas pakeičiant tarpus brūkšneliais. Rezultatas neturi būti galiojantis Ruby identifikatorius - pavadinimas gali turėti skyrybos ženklų ir t.t. Tai yra todėl, kad Ruby techniškai bet koks eilutė gali būti metodo pavadinimu. Tai gali reikalauti define_method ir send iškvietimų, kad veiktų tinkamai, tačiau formaliai pavadinimui yra mažai apribojimų.

Toliau pažvelkime į pirmąją mūsų patikrinimą:

assert true

Patikrinimas yra kodo eilutė, kuri vertina objektą (arba išraišką) pagal tikėtus rezultatus. Pavyzdžiui, patikrinimas gali patikrinti:

  • ar ši vertė = ta vertė?
  • ar šis objektas yra tuščias?
  • ar ši kodo eilutė išmeta išimtį?
  • ar vartotojo slaptažodis yra ilgesnis nei 5 simboliai?

Kiekvienas testas gali turėti vieną ar daugiau patikrinimų, be jokių apribojimų, kiek patikrinimų leidžiama. Tik kai visi patikrinimai sėkmingi, testas bus sėkmingas.

2.3.1 Jūsų pirmas nesėkmingas testas

Norėdami pamatyti, kaip pranešama apie nesėkmingą testą, galite pridėti nesėkmingą testą prie article_test.rb testo atvejo.

test "neturėtų išsaugoti straipsnio be pavadinimo" do
  article = Article.new
  assert_not article.save
end

Paleiskime šį naujai pridėtą testą (kur 6 yra eilutės numeris, kurioje apibrėžiamas testas).

$ bin/rails test test/models/article_test.rb:6
Run options: --seed 44656

# Running:

F

Failure:
ArticleTest#test_should_not_save_article_without_title [/path/to/blog/test/models/article_test.rb:6]:
Expected true to be nil or false


bin/rails test test/models/article_test.rb:6



Finished in 0.023918s, 41.8090 runs/s, 41.8090 assertions/s.

1 runs, 1 assertions, 1 failures, 0 errors, 0 skips

Išvestyje F žymi nesėkmę. Galite pamatyti atitinkamą seką, rodomą po Failure, kartu su nesėkmingo testo pavadinimu. Keli kitos eilutės yra steko sekos, po to yra pranešimas, kuriame paminėta tikroji ir tikėtina reikšmė, kurią nurodo patikrinimas. Numatyti patikrinimo pranešimai suteikia pakankamai informacijos, kad padėtų nustatyti klaidą. Norint padaryti patikrinimo nesėkmės pranešimą aiškesnį, kiekvienas patikrinimas suteikia pasirinktinį pranešimo parametrą, kaip parodyta čia:

test "neturėtų išsaugoti straipsnio be pavadinimo" do
  article = Article.new
  assert_not article.save, "Išsaugotas straipsnis be pavadinimo"
end

Paleidus šį testą, rodomas draugiškesnis patikrinimo pranešimas:

Failure:
ArticleTest#test_should_not_save_article_without_title [/path/to/blog/test/models/article_test.rb:6]:
Išsaugotas straipsnis be pavadinimo

Dabar, norint, kad šis testas būtų sėkmingas, galime pridėti modelio lygio tikrinimą title laukui.

class Article < ApplicationRecord
  validates :title, presence: true
end

Dabar testas turėtų būti sėkmingas. Patikrinkime paleidę testą dar kartą:

$ bin/rails test test/models/article_test.rb:6
Run options: --seed 31252

# Running:

.

Finished in 0.027476s, 36.3952 runs/s, 36.3952 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

Dabar, jei pastebėjote, mes pirmiausia parašėme testą, kuris nepavyksta norimai funkcionalumui, tada parašėme kodą, kuris prideda funkcionalumą, ir galiausiai užtikrinome, kad mūsų testas būtų sėkmingas. Šis požiūris į programinės įrangos kūrimą vadinamas Test-Driven Development (TDD).

2.3.2 Kaip atrodo klaida

Norėdami pamatyti, kaip pranešama apie klaidą, čia yra testas, kuriame yra klaida:

test "turėtų pranešti apie klaidą" do
  # some_undefined_variable nėra apibrėžta kitur testo atveju
  some_undefined_variable
  assert true
end

Dabar konsolėje galite pamatyti dar daugiau išvesties išvykstant testus:

$ bin/rails test test/models/article_test.rb
Run options: --seed 1808

# Running:

.E

Klaida:
ArticleTest#test_should_report_error:
NameError: kintamasis arba metodas 'some_undefined_variable' nėra apibrėžtas #<ArticleTest:0x007fee3aa71798>
    test/models/article_test.rb:11:in 'block in <class:ArticleTest>'


bin/rails test test/models/article_test.rb:9



Baigta per 0.040609s, 49.2500 vykdymų/s, 24.6250 tikrinimų/s.

2 vykdymai, 1 tikrinimas, 0 nesėkmės, 1 klaida, 0 praleidimai

Pastebėkite 'E' išvestyje. Tai žymi testą su klaida.

PASTABA: Kiekvieno testo metodo vykdymas sustoja, kai randama klaida arba tikrinimo nesėkmė, o testų rinkinys tęsiasi su kitu metodu. Visi testo metodai vykdomi atsitiktine tvarka. config.active_support.test_order parinktis gali būti naudojama konfigūruoti testų tvarką.

Kai testas nepavyksta, jums pateikiamas atitinkamas atgalinės sekos žemėlapis. Pagal numatytuosius nustatymus „Rails“ filtruoja tą atgalinės sekos žemėlapį ir spausdina tik jūsų programai svarbias eilutes. Tai pašalina pagrindinio pagrindo triukšmą ir padeda sutelkti dėmesį į jūsų kodą. Tačiau yra situacijų, kai norite pamatyti visą atgalinės sekos žemėlapį. Nustatykite -b (arba --backtrace) argumentą, kad įgalintumėte šį veiksmą:

$ bin/rails test -b test/models/article_test.rb

Jei norime, kad šis testas pavyktų, galime jį pakeisti naudodami assert_raises taip:

test "should report error" do
  # some_undefined_variable kitur testo atveju nėra apibrėžtas
  assert_raises(NameError) do
    some_undefined_variable
  end
end

Šis testas dabar turėtų pavykti.

2.4 Prieinami tikrinimai

Jau matėte keletą prieinamų tikrinimų. Tikrinimai yra testavimo darbininkai. Jie yra tie, kurie iš tikrųjų atlieka patikrinimus, kad būtų užtikrinta, jog viskas vyksta kaip planuota.

Čia pateikiamas ištraukos iš tikrinimų, kuriuos galite naudoti su Minitest, pagal nutylėjimą naudojamu testavimo biblioteka naudojama „Rails“. [msg] parametras yra pasirinktinis eilutės žinutė, kurią galite nurodyti, kad padarytumėte aiškesnes testo nesėkmės žinutes.

Tikrinimas Tikslas
assert( test, [msg] ) Užtikrina, kad test būtų teisingas.
assert_not( test, [msg] ) Užtikrina, kad test būtų neteisingas.
assert_equal( expected, actual, [msg] ) Užtikrina, kad expected == actual būtų teisinga.
assert_not_equal( expected, actual, [msg] ) Užtikrina, kad expected != actual būtų teisinga.
assert_same( expected, actual, [msg] ) Užtikrina, kad expected.equal?(actual) būtų teisinga.
assert_not_same( expected, actual, [msg] ) Užtikrina, kad expected.equal?(actual) būtų neteisinga.
assert_nil( obj, [msg] ) Užtikrina, kad obj.nil? būtų teisinga.
assert_not_nil( obj, [msg] ) Užtikrina, kad obj.nil? būtų neteisinga.
assert_empty( obj, [msg] ) Užtikrina, kad obj yra empty?.
assert_not_empty( obj, [msg] ) Užtikrina, kad obj nėra empty?.
assert_match( regexp, string, [msg] ) Užtikrina, kad eilutė atitinka reguliariąją išraišką.
assert_no_match( regexp, string, [msg] ) Užtikrina, kad eilutė neatitinka reguliariąją išraišką.
assert_includes( collection, obj, [msg] ) Užtikrina, kad obj yra collection.
assert_not_includes( collection, obj, [msg] ) Užtikrina, kad obj nėra collection.
assert_in_delta( expected, actual, [delta], [msg] ) Užtikrina, kad skaičiai expected ir actual yra vienas kitam arti delta.
assert_not_in_delta( expected, actual, [delta], [msg] ) Užtikrina, kad skaičiai expected ir actual nėra vienas kitam arti delta.
assert_in_epsilon ( expected, actual, [epsilon], [msg] ) Užtikrina, kad skaičiai expected ir actual turi santykinį klaidą mažesnę nei epsilon.
assert_not_in_epsilon ( expected, actual, [epsilon], [msg] ) Užtikrina, kad skaičiai expected ir actual turi santykinį klaidą, kuri nėra mažesnė nei epsilon.
assert_throws( symbol, [msg] ) { block } Užtikrina, kad duotas blokas išmeta simbolį.
assert_raises( exception1, exception2, ... ) { block } Užtikrina, kad duotas blokas iškelia vieną iš duotų išimčių.
assert_instance_of( class, obj, [msg] ) Užtikrina, kad obj yra class pavyzdys.
assert_not_instance_of( class, obj, [msg] ) Užtikrina, kad obj nėra class pavyzdys.
assert_kind_of( class, obj, [msg] ) Užtikrina, kad obj yra class pavyzdys arba jam paveldima.
assert_not_kind_of( class, obj, [msg] ) Užtikrina, kad obj nėra class pavyzdys ir jam nėra paveldima.
assert_respond_to( obj, symbol, [msg] ) Užtikrina, kad obj atsako į symbol.
assert_not_respond_to( obj, symbol, [msg] ) Užtikrina, kad obj neatstoja symbol.
assert_operator( obj1, operator, [obj2], [msg] ) Užtikrina, kad obj1.operator(obj2) yra teisinga.
assert_not_operator( obj1, operator, [obj2], [msg] ) Užtikrina, kad obj1.operator(obj2) yra neteisinga.
assert_predicate ( obj, predicate, [msg] ) Užtikrina, kad obj.predicate yra teisinga, pvz., assert_predicate str, :empty?
assert_not_predicate ( obj, predicate, [msg] ) Užtikrina, kad obj.predicate yra neteisinga, pvz., assert_not_predicate str, :empty?
flunk( [msg] ) Užtikrina nesėkmę. Tai naudinga, norint aiškiai pažymėti testą, kuris dar nėra baigtas.

Aukščiau pateikti teiginiai yra tik dalis teiginių, kuriuos palaiko minitest. Išsamią ir naujausią sąrašą galite rasti Minitest API dokumentacijoje, konkrečiai Minitest::Assertions.

Dėl testavimo pagrindo modularumo, galima kurti savo teiginius. Iš tikrųjų, tai yra tai, ką daro "Rails". Jis įtraukia keletą specializuotų teiginių, kad jums būtų lengviau.

PASTABA: Savo teiginių kūrimas yra sudėtinga tema, kurią šiame vadove aptarti neketiname.

2.5 "Rails" konkretūs teiginiai

"Rails" į minitest pagrindą prideda savo pritaikytų teiginių:

Teiginys Tikslas
assert_difference(expressions, difference = 1, message = nil) {...} Patikrinti skaitinį skirtumą tarp išraiškos grąžinimo vertės kaip rezultato, kuris yra vertinamas per perduodamą bloką.
assert_no_difference(expressions, message = nil, &block) Patvirtina, kad skaitinės išraiškos vertė nepasikeitė prieš ir po perduoto bloko iškvietimo.
assert_changes(expressions, message = nil, from:, to:, &block) Patikrinti, ar išraiškos vertė pasikeitė po perduoto bloko iškvietimo.
assert_no_changes(expressions, message = nil, &block) Patikrinti, ar išraiškos vertė nepasikeitė po perduoto bloko iškvietimo.
assert_nothing_raised { block } Užtikrina, kad pateiktas blokas neperskeltų jokių išimčių.
assert_recognizes(expected_options, path, extras={}, message=nil) Patvirtina, kad nurodyto kelio maršrutizavimas buvo tvarkingas ir kad analizuoti parametrai (duoti expected_options hae) atitinka kelią. Iš esmės, tai patvirtina, kad "Rails" atpažįsta maršrutą, kurį nurodo expected_options.
assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) Patvirtina, kad pateikti parametrai gali būti naudojami generuoti pateiktą kelią. Tai yra atvirkštinis veiksmas nei assert_recognizes. "Extras" parametras naudojamas nurodyti papildomų užklausos parametrų pavadinimus ir reikšmes, kurios būtų užklausos eilutėje. "Message" parametras leidžia nurodyti pasirinktinį klaidos pranešimą, jei patikrinimas nepavyksta.
assert_response(type, message = nil) Patvirtina, kad atsakas turi tam tikrą būsenos kodą. Galite nurodyti :success, jei norite nurodyti 200-299, :redirect, jei norite nurodyti 300-399, :missing, jei norite nurodyti 404, arba :error, jei norite atitikti 500-599 intervalą. Taip pat galite perduoti konkretų būsenos numerį arba jo simbolinį ekvivalentą. Daugiau informacijos rasite visų būsenos kodų ir jų atitikmenų sąraše.
assert_redirected_to(options = {}, message=nil) Patvirtina, kad atsakas yra peradresuojamas į URL, atitinkantį nurodytus parametrus. Taip pat galite perduoti pavadinimus turinčius maršrutus, pvz., assert_redirected_to root_path, ir "Active Record" objektus, pvz., assert_redirected_to @article.

Kitame skyriuje pamatysite, kaip naudoti kai kuriuos iš šių teiginių.

2.6 Trumpas pastebėjimas apie testavimo atvejus

Visi pagrindiniai teiginiai, tokie kaip assert_equal, apibrėžti Minitest::Assertions, taip pat yra prieinami klasėse, kurias naudojame savo testavimo atvejuose. Iš tikrųjų, "Rails" suteikia šias klases, kurias galite paveldėti:

Kiekviena iš šių klasių įtraukia Minitest::Assertions, leidžiant mums naudoti visus pagrindinius teiginius savo testuose.

PASTABA: Daugiau informacijos apie Minitest rasite jo dokumentacijoje.

2.7 "Rails" testų paleidimas

Visus testus galime paleisti vienu metu naudodami bin/rails test komandą.

Arba galime paleisti vieną testų failą perduodami bin/rails test komandai failo pavadinimą, kuriame yra testavimo atvejai.

$ bin/rails test test/models/article_test.rb
Run options: --seed 1559

# Running:

..

Finished in 0.027034s, 73.9810 runs/s, 110.9715 assertions/s.

2 runs, 3 assertions, 0 failures, 0 errors, 0 skips

Tai paleis visus testo metodus iš testavimo atvejo. Norint paleisti tam tikrą testo metodą iš testo atvejo, galite nurodyti -n arba --name žymeklį ir testo metodo pavadinimą.

$ bin/rails test test/models/article_test.rb -n test_the_truth
Vykdomi parametrai: -n test_the_truth --seed 43583

# Vykdoma:

.

Baigti testai per 0.009064 s, 110.3266 testai/s, 110.3266 patvirtinimai/s.

1 testas, 1 patvirtinimas, 0 nesėkmės, 0 klaidos, 0 praleidimai

Taip pat galite paleisti testą tam tikroje eilutėje nurodydami eilutės numerį.

$ bin/rails test test/models/article_test.rb:6 # paleisti konkretų testą ir eilutę

Taip pat galite paleisti visą testų katalogą nurodydami katalogo kelią.

$ bin/rails test test/controllers # paleisti visus testus iš konkretaus katalogo

Testų vykdyklė taip pat teikia daug kitų funkcijų, pvz., greito nesėkmės atveju, atidėti testo rezultatų išvestį iki testo vykdymo pabaigos ir t.t. Patikrinkite testų vykdyklės dokumentaciją kaip nurodyta žemiau:

$ bin/rails test -h
Naudojimas: rails test [parametrai] [failai arba katalogai]

Vieną testą galite paleisti pridedant eilutės numerį prie failo pavadinimo:

    bin/rails test test/models/user_test.rb:27

Galite paleisti kelis failus ir katalogus vienu metu:

    bin/rails test test/controllers test/integration/login_test.rb

Pagal numatytuosius nustatymus testų nesėkmės ir klaidos pranešamos tiesiogiai vykdymo metu.

minitest parametrai:
    -h, --help                       Rodyti šią pagalbą.
        --no-plugins                 Apeiti minitest įskiepių automatinį įkėlimą (arba nustatyti $MT_NO_PLUGINS).
    -s, --seed SEED                  Nustato atsitiktinį sėklą. Taip pat per aplinką. Pvz.: SEED=n rake
    -v, --verbose                    Išsamus. Rodyti progreso informaciją apie failų apdorojimą.
    -n, --name PATTERN               Filtruoti pagal /regexp/ arba eilutę.
        --exclude PATTERN            Pašalinti /regexp/ arba eilutę iš vykdymo.

Žinomi plėtiniai: rails, pride
    -w, --warnings                   Paleisti su įjungtomis Ruby įspėjimais
    -e, --environment ENV            Paleisti testus ENV aplinkoje
    -b, --backtrace                  Rodyti visą atkarpą
    -d, --defer-output               Išvesti testų nesėkmes ir klaidas po testo vykdymo
    -f, --fail-fast                  Nutraukti testo vykdymą pirmoje nesėkmėje arba klaidoje
    -c, --[no-]color                 Įjungti spalvą išvestyje
    -p, --pride                      Pasididžiuokite savo testavimo pasiekimais!

2.8 Testų vykdymas nuolatinėje integracijoje (CI)

Norint paleisti visus testus nuolatinėje integracijos aplinkoje, jums tereikia vieno komandos:

$ bin/rails test

Jei naudojate Sistemos testus, bin/rails test jų nevykdys, nes jie gali būti lėti. Norėdami juos taip pat paleisti, pridėkite dar vieną CI žingsnį, kuris paleidžia bin/rails test:system, arba pakeiskite pirmąjį žingsnį į bin/rails test:all, kuris paleidžia visus testus, įskaitant sistemos testus.

3 Lygiagretus testavimas

Lygiagretus testavimas leidžia jums lygiagrečiai vykdyti testų rinkinį. Nors numatytasis būdas yra kurti procesus naudojant Ruby DRb sistemą, taip pat palaikomas gijų naudojimas. Lygiagretus testavimas sumažina laiką, kurį užtrunka viso testų rinkinio vykdymas.

3.1 Lygiagretus testavimas naudojant procesus

Numatytasis lygiagretinimo būdas yra kurti procesus naudojant Ruby DRb sistemą. Procesai yra kuriama pagal pateiktų darbuotojų skaičių. Numatytasis skaičius yra faktinis branduolių skaičius jūsų mašinoje, bet jį galima pakeisti perduodant skaičių parallelize metodui.

Norėdami įgalinti lygiagretinimą, pridėkite šį kodą į savo test_helper.rb:

class ActiveSupport::TestCase
  parallelize(workers: 2)
end

Perduodamas darbuotojų skaičius yra procesų kūrimo skaičius. Galite norėti lygiagrečiai vykdyti vietinį testų rinkinį kitaip nei CI, todėl aplinkos kintamasis suteikiamas galimybę lengvai keisti darbuotojų skaičių, kurį testų vykdymas turėtų naudoti:

$ PARALLEL_WORKERS=15 bin/rails test

Lygiagretinant testus, Active Record automatiškai tvarko duomenų bazės kūrimą ir schemos įkėlimą į duomenų bazę kiekvienam procesui. Duomenų bazės bus papildytos numeriu, atitinkančiu darbuotoją. Pavyzdžiui, jei turite 2 darbuotojus, testai sukurs test-database-0 ir test-database-1 atitinkamai. Jei perduodamų darbuotojų skaičius yra 1 ar mažesnis, procesai nebus šakojami ir testai nebus parallelizuojami, o testai naudos originalią test-database duomenų bazę.

Pateikiami du kablys, vienas veikia, kai procesas yra šakojamas, o kitas veikia prieš uždarant šakotą procesą. Tai gali būti naudinga, jei jūsų programa naudoja kelias duomenų bazes arba atlieka kitus uždavinius, priklausančius nuo darbuotojų skaičiaus.

parallelize_setup metodas yra iškviečiamas tuoj pat po proceso šakojimo. parallelize_teardown metodas yra iškviečiamas tuoj pat prieš procesų uždarymą.

class ActiveSupport::TestCase
  parallelize_setup do |worker|
    # duomenų bazių nustatymas
  end

  parallelize_teardown do |worker|
    # duomenų bazių valymas
  end

  parallelize(workers: :number_of_processors)
end

Šie metodai nėra reikalingi ir neprieinami naudojant parallelizuotą testavimą su gijomis.

3.2 Parallelizuotas testavimas su gijomis

Jei norite naudoti gijas arba naudojate JRuby, pateikiama paralelizavimo su gijomis parinktis. Gijų paralelizatorius remiasi Minitest Parallel::Executor.

Norėdami pakeisti paralelizavimo metodą naudoti gijas vietoj šakojimo, įkelkite šį kodą į savo test_helper.rb

class ActiveSupport::TestCase
  parallelize(workers: :number_of_processors, with: :threads)
end

Iš JRuby ar TruffleRuby sugeneruotos "Rails" programos automatiškai įtraukia with: :threads parinktį.

Darbuotojų skaičius, perduotas parallelize metodui, nustato testų gijų skaičių. Galbūt norėsite skirtingai parallelizuoti vietinį testų rinkinį ir CI, todėl pateikiama aplinkos kintamoji, leidžianti lengvai keisti darbuotojų skaičių testų vykdymui:

$ PARALLEL_WORKERS=15 bin/rails test

3.3 Testavimas su parallelizuotais sandoriais

"Rails" automatiškai apgaubia bet kurį testo atvejį duomenų bazės sandoriu, kuris yra atšaukiamas po testo pabaigos. Tai padaro testo atvejus nepriklausomus vienas nuo kito, o duomenų bazės pakeitimai matomi tik viename teste.

Kai norite testuoti kodą, kuris vykdo parallelizuotus sandorius gijose, sandoriai gali blokuoti vienas kitą, nes jie jau yra įdėti į testo sandorį.

Galite išjungti sandorius testo atvejo klasėje, nustatydami self.use_transactional_tests = false:

class WorkerTest < ActiveSupport::TestCase
  self.use_transactional_tests = false

  test "parallelizuoti sandoriai" do
    # paleiskite kelias gijas, kurios kuria sandorius
  end
end

PASTABA: Išjungus sandorių testus, turite išvalyti bet kokius duomenis, kuriuos testai sukuria, nes pakeitimai po testo pabaigos nebus automatiškai atšaukti.

3.4 Sluoksnis, skirtas testų parallelizavimo slenkstui

Testų vykdymas paralleliai sukelia papildomą apkrovą, susijusią su duomenų bazės nustatymu ir fiktyvių duomenų įkėlimu. Dėl šios priežasties "Rails" nevykdo parallelizuotų vykdymų, kuriuose dalyvauja mažiau nei 50 testų.

Galite konfigūruoti šį slenkstį savo test.rb:

config.active_support.test_parallelization_threshold = 100

Taip pat nustatant parallelizavimą testo atvejo lygyje:

class ActiveSupport::TestCase
  parallelize threshold: 100
end

4 Testinė duomenų bazė

Beveik kiekviena "Rails" programa labai sąveikauja su duomenų baze, todėl jūsų testai taip pat turės sąveikauti su duomenų baze. Norėdami rašyti efektyvius testus, turėsite suprasti, kaip nustatyti šią duomenų bazę ir ją užpildyti pavyzdiniais duomenimis.

Pagal numatytuosius nustatymus kiekviena "Rails" programa turi tris aplinkas: vystymąsi, testavimą ir produkciją. Kiekvienai iš jų duomenų bazė yra konfigūruojama config/database.yml.

Atskira testinė duomenų bazė leidžia jums izoliuotai nustatyti ir sąveikauti su testiniais duomenimis. Taip jūsų testai gali drąsiai manipuliuoti testiniais duomenimis, nesijaudindami dėl duomenų vystymo ar produkcijos duomenų bazėse.

4.1 Testinės duomenų bazės schemos palaikymas

Norėdami paleisti savo testus, jūsų testinė duomenų bazė turės turėti dabartinę struktūrą. Testo pagalbininkas patikrina, ar jūsų testinė duomenų bazė turi nepatvirtintų migracijų. Jis bandys įkelti jūsų db/schema.rb arba db/structure.sql į testinę duomenų bazę. Jei migracijos dar nepatvirtintos, bus iškelta klaida. Paprastai tai reiškia, kad jūsų schema nėra visiškai migruota. Paleidus migracijas prieš vystymo duomenų bazę (bin/rails db:migrate), schema bus atnaujinta. PASTABA: Jei buvo atlikti pakeitimai esamoms migracijoms, testinė duomenų bazė turi būti atstatyta. Tai galima padaryti vykdant bin/rails db:test:prepare.

4.2 Apie fiktyvius duomenis

Norint gauti gerus testus, reikia apgalvoti testinių duomenų nustatymą. „Rails“ galima tai padaryti apibrėžiant ir pritaikant fiktyvius duomenis. Išsamią dokumentaciją rasite Fiktyvių duomenų API dokumentacijoje.

4.2.1 Kas yra fiktyvūs duomenys?

Fiktyvūs duomenys yra sudėtingas žodis, reiškiantis pavyzdinius duomenis. Fiktyvūs duomenys leidžia užpildyti jūsų testinę duomenų bazę su iš anksto nustatytais duomenimis prieš paleidžiant testus. Fiktyvūs duomenys yra nepriklausomi nuo duomenų bazės ir parašyti YAML formatu. Kiekvienam modeliui yra vienas failas.

PASTABA: Fiktyvūs duomenys nėra skirti kurti visus objektus, kurių jums reikia testuose, ir geriausiai tvarkomi, kai naudojami tik numatytieji duomenys, kurie gali būti pritaikyti bendrai atvejai.

Fiktyvius duomenis rasite savo test/fixtures kataloge. Paleidus bin/rails generate model, kuriant naują modelį, „Rails“ automatiškai sukuria fiktyvius duomenis šiame kataloge.

4.2.2 YAML

YAML formatuoti fiktyvūs duomenys yra draugiškas žmogui būdas aprašyti pavyzdinius duomenis. Tokio tipo fiktyvūs duomenys turi .yml failo plėtinį (pvz., users.yml).

Štai pavyzdinis YAML fiktyvų duomenų failas:

# štai ir aš, YAML komentaras!
david:
  name: David Heinemeier Hansson
  birthday: 1979-10-15
  profession: Sistemos kūrimas

steve:
  name: Steve Ross Kellock
  birthday: 1974-09-27
  profession: žmogus su klaviatūra

Kiekvienam fiktyviam duomeniui suteikiamas pavadinimas, po to seka įtrauktų raktų ir reikšmių sąrašas, atskirtas dvitaškiais. Įrašai paprastai yra atskirti tuščia eilute. Komentarus galite įterpti į fiktyvų duomenų failą naudodami # simbolį pirmame stulpelyje.

Jei dirbate su asociacijomis, galite apibrėžti nuorodos mazgą tarp dviejų skirtingų fiktyvių duomenų. Štai pavyzdys su belongs_to/has_many asociacija:

# test/fixtures/categories.yml
about:
  name: Apie
# test/fixtures/articles.yml
first:
  title: Sveiki atvykę į „Rails“!
  category: about
# test/fixtures/action_text/rich_texts.yml
first_content:
  record: first (Article)
  name: turinys
  body: <div>Sveiki, iš <strong>fiktyvaus duomenų failo</strong></div>

Pastebėkite, kad first straipsnio category raktas, randamas fixtures/articles.yml, turi reikšmę about, o first_content įrašo record raktas, randamas fixtures/action_text/rich_texts.yml, turi reikšmę first (Article). Tai užuotinuoja „Active Record“ įkelti kategoriją about, randamą fixtures/categories.yml, pirmajam atvejui, ir „Action Text“ įkelti straipsnį first, randamą fixtures/articles.yml, antrajam atvejui.

PASTABA: Norint, kad asociacijos viena kitą nuorodytų pagal pavadinimą, galite naudoti fiktyvų pavadinimą, vietoj to, kad nurodytumėte id: atributą asocijuotuose fiktyviuose duomenyse. „Rails“ automatiškai priskirs pagrindinį raktą, kad būtų išlaikytas nuoseklumas tarp paleidimų. Daugiau informacijos apie šią asociacijos elgseną galite rasti Fiktyvių duomenų API dokumentacijoje.

4.2.3 Failo prikabos fiktyvūs duomenys

Kaip ir kiti „Active Record“ palaikomi modeliai, „Active Storage“ prikabos įrašai paveldi iš „ActiveRecord::Base“ pavyzdžių ir todėl gali būti užpildyti fiktyviais duomenimis.

Pavyzdžiui, turime „Article“ modelį, kuris turi susijusį paveikslėlį kaip „thumbnail“ prikabą, kartu su fiktyviais duomenimis YAML formatu:

class Article
  has_one_attached :thumbnail
end
# test/fixtures/articles.yml
first:
  title: Straipsnis

Tarkime, kad yra image/png koduotas failas test/fixtures/files/first.png. Šie YAML fiktyvūs įrašai sukurs susijusius ActiveStorage::Blob ir ActiveStorage::Attachment įrašus:

# test/fixtures/active_storage/blobs.yml
first_thumbnail_blob: <%= ActiveStorage::FixtureSet.blob filename: "first.png" %>
# test/fixtures/active_storage/attachments.yml
first_thumbnail_attachment:
  name: thumbnail
  record: first (Article)
  blob: first_thumbnail_blob

4.2.4 ERB

ERB leidžia įterpti „Ruby“ kodą į šablonus. YAML fiktyvų duomenų formatas yra apdorojamas su ERB, kai „Rails“ įkelia fiktyvius duomenis. Tai leidžia naudoti „Ruby“ pagalbą generuojant pavyzdinius duomenis. Pavyzdžiui, šis kodas sugeneruoja tūkstantį vartotojų:

<% 1000.times do |n| %>
user_<%= n %>:
  username: <%= "user#{n}" %>
  email: <%= "user#{n}@example.com" %>
<% end %>

4.2.5 Veikiantys fiksuojamieji duomenys

Pagal numatytuosius nustatymus "Rails" automatiškai įkelia visus fiksuojamuosius duomenis iš test/fixtures katalogo. Įkėlimas apima tris žingsnius:

  1. Pašalinti bet kokius esamus duomenis iš lentelės, atitinkančios fiksuojamąjį duomenį
  2. Įkelti fiksuojamąjį duomenį į lentelę
  3. Iškrauti fiksuojamąjį duomenį į metodą, jei norite prie jo tiesiogiai prieiti

PATARIMAS: Norėdami pašalinti esamus duomenis iš duomenų bazės, "Rails" bando išjungti nuorodinės vientisumo trigerius (tokius kaip užsienio raktai ir patikros apribojimai). Jei paleidžiant testus gaunate erzinančius leidimo klaidas, įsitikinkite, kad duomenų bazės naudotojas turi teisę išjungti šiuos trigerius testavimo aplinkoje. (PostgreSQL duomenų bazėje visi trigerius gali išjungti tik super naudotojai. Daugiau informacijos apie PostgreSQL leidimus galite rasti čia).

4.2.6 Fiksuojamieji duomenys yra aktyvūs įrašų objektai

Fiksuojamieji duomenys yra "Active Record" objektų pavyzdžiai. Kaip minėta 3 punkte aukščiau, galite tiesiogiai pasiekti objektą, nes jis automatiškai yra prieinamas kaip metodas, kurio taikymo sritis yra vietinė testo atvejo. Pavyzdžiui:

# tai grąžins "User" objektą, kuris atitinka fiksuojamąjį duomenį su pavadinimu "david"
users(:david)

# tai grąžins "david" savybę, vadinamą "id"
users(:david).id

# taip pat galima pasiekti metodus, kurie yra prieinami "User" klasėje
david = users(:david)
david.call(david.partner)

Norėdami gauti kelis fiksuojamuosius duomenis vienu metu, galite perduoti sąrašą su fiksuojamųjų duomenų pavadinimais. Pavyzdžiui:

# tai grąžins masyvą, kuriame bus fiksuojamieji duomenys "david" ir "steve"
users(:david, :steve)

5 Modelio testavimas

Modelio testai naudojami testuoti jūsų aplikacijos įvairius modelius.

"Rails" modelio testai saugomi test/models kataloge. "Rails" teikia generatorių, kuris sukurs modelio testo struktūrą jums.

$ bin/rails generate test_unit:model article title:string body:text
create  test/models/article_test.rb
create  test/fixtures/articles.yml

Modelio testai neturi savo superklasės, kaip ActionMailer::TestCase. Vietoj to, jie paveldi ActiveSupport::TestCase.

6 Sistemos testavimas

Sistemos testai leidžia jums testuoti vartotojų sąveiką su jūsų aplikacija, vykdyti testus realiame arba begaliniame naršyklėje. Sistemos testai naudoja "Capybara" pagrindu.

Norėdami sukurti "Rails" sistemos testus, naudokite test/system katalogą savo aplikacijoje. "Rails" teikia generatorių, kuris sukurs sistemos testo struktūrą jums.

$ bin/rails generate system_test users
      invoke test_unit
      create test/system/users_test.rb

Štai kaip atrodo naujai sukurtas sistemos testas:

require "application_system_test_case"

class UsersTest < ApplicationSystemTestCase
  # test "visiting the index" do
  #   visit users_url
  #
  #   assert_selector "h1", text: "Users"
  # end
end

Pagal numatytuosius nustatymus sistemos testai vykdomi naudojant "Selenium" draiverį, naudojant "Chrome" naršyklę ir ekrano dydžiu 1400x1400. Kitame skyriuje paaiškinama, kaip pakeisti numatytuosius nustatymus.

6.1 Numatytųjų nustatymų keitimas

"Rails" labai paprastai keičia numatytuosius sistemos testų nustatymus. Visi sąranka yra paslėpta, todėl galite sutelkti dėmesį į savo testų rašymą.

Kai generuojate naują aplikaciją arba šabloną, application_system_test_case.rb failas sukuriamas testų kataloge. Čia turėtų būti visi sistemos testų konfigūracijos nustatymai.

Jei norite pakeisti numatytuosius nustatymus, galite pakeisti tai, kuo sistemos testai yra "valdomi". Tarkime, norite pakeisti "Selenium" draiverį į "Cuprite". Pirmiausia pridėkite cuprite giją į savo Gemfile. Tada savo application_system_test_case.rb faile atlikite šiuos veiksmus:

require "test_helper"
require "capybara/cuprite"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  driven_by :cuprite
end

Vairuotojo pavadinimas yra privalomas argumentas driven_by. Galimi pasirinktiniai argumentai, kurie gali būti perduoti driven_by, yra :using naršyklės (tai bus naudojama tik "Selenium"), :screen_size norint pakeisti ekrano dydį ekranų nuotraukoms ir :options, kurie gali būti naudojami nustatyti vairuotojo palaikomus parametrus.

require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  driven_by :selenium, using: :firefox
end

Jei norite naudoti be galvos naršyklę, galite naudoti "Headless Chrome" arba "Headless Firefox", pridedant headless_chrome arba headless_firefox į :using argumentą.

require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  driven_by :selenium, using: :headless_chrome
end

Jei norite naudoti nuotolinę naršyklę, pvz., Headless Chrome Docker, turite pridėti nuotolinį url per options.

require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  options = ENV["SELENIUM_REMOTE_URL"].present? ? { url: ENV["SELENIUM_REMOTE_URL"] } : {}
  driven_by :selenium, using: :headless_chrome, options: options
end

Tokiu atveju, daugiau nereikalingas webdrivers gembė. Jį galite visiškai pašalinti arba pridėti require: opciją Gemfile.

# ...
group :test do
  gem "webdrivers", require: !ENV["SELENIUM_REMOTE_URL"] || ENV["SELENIUM_REMOTE_URL"].empty?
end

Dabar turėtumėte gauti ryšį su nuotoline naršykle.

$ SELENIUM_REMOTE_URL=http://localhost:4444/wd/hub bin/rails test:system

Jei jūsų testuojama aplikacija taip pat veikia nuotoliniame režime, pvz., Docker konteineryje, Capybara reikia daugiau informacijos apie tai, kaip skambinti nuotoliniams serveriams.

require "test_helper"

class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
  def setup
    Capybara.server_host = "0.0.0.0" # susieti su visais sąsajomis
    Capybara.app_host = "http://#{IPSocket.getaddress(Socket.gethostname)}" if ENV["SELENIUM_REMOTE_URL"].present?
    super
  end
  # ...
end

Dabar turėtumėte gauti ryšį su nuotoline naršykle ir serveriu, nepriklausomai nuo to, ar jis veikia Docker konteineryje ar CI.

Jei jūsų Capybara konfigūracija reikalauja daugiau nustatymų nei pateikia Rails, šią papildomą konfigūraciją galima pridėti į application_system_test_case.rb failą.

Papildomus nustatymus rasite Capybara dokumentacijoje.

6.2 Screenshot Helper

ScreenshotHelper yra pagalbinė priemonė, skirta užfiksuoti jūsų testų ekrano kopijas. Tai gali būti naudinga, norint peržiūrėti naršyklę, kai testas nepavyksta, arba vėliau peržiūrėti ekrano kopijas, norint atlikti klaidų šalinimą.

Pateikiami du metodai: take_screenshot ir take_failed_screenshot. take_failed_screenshot automatiškai įtraukiamas į before_teardown viduje Rails.

take_screenshot pagalbinis metodas gali būti įtrauktas bet kur jūsų testuose, norint užfiksuoti naršyklės ekrano kopiją.

6.3 Sistemos testo įgyvendinimas

Dabar pridėsime sistemos testą į mūsų tinklaraščio aplikaciją. Demonstruosime sistemos testo rašymą, apsilankydami indekso puslapyje ir sukurdami naują tinklaraščio straipsnį.

Jei naudojote šablonų generatorių, jums automatiškai buvo sukurtas sistemos testo šablonas. Jei nenaudojote šablono generatoriaus, pradėkite nuo sistemos testo šablono sukūrimo.

$ bin/rails generate system_test articles

Jis turėjo sukurti testo failo šabloną. Su ankstesnio komandos rezultatu turėtumėte matyti:

      invoke  test_unit
      create    test/system/articles_test.rb

Dabar atidarykime tą failą ir parašykime pirmąjį patikrinimą:

require "application_system_test_case"

class ArticlesTest < ApplicationSystemTestCase
  test "viewing the index" do
    visit articles_path
    assert_selector "h1", text: "Articles"
  end
end

Testas turėtų matyti, kad straipslių indekso puslapyje yra h1 ir sėkmingai pereiti.

Paleiskite sistemos testus.

$ bin/rails test:system

PASTABA: Pagal numatytuosius nustatymus, paleidus bin/rails test nebus paleisti jūsų sistemos testai. Įsitikinkite, kad paleidote bin/rails test:system, kad juos iš tikrųjų paleistumėte. Taip pat galite paleisti bin/rails test:all, kad paleistumėte visus testus, įskaitant sistemos testus.

6.3.1 Straipslių sistemos testo kūrimas

Dabar išbandykime srauto kūrimo naujam straipsniui mūsų tinklaraštyje.

test "should create Article" do
  visit articles_path

  click_on "New Article"

  fill_in "Title", with: "Creating an Article"
  fill_in "Body", with: "Created this article successfully!"

  click_on "Create Article"

  assert_text "Creating an Article"
end

Pirmas žingsnis yra iškviesti visit articles_path. Tai nukreips testą į straipslių indekso puslapį.

Tada click_on "New Article" ras "New Article" mygtuką indekso puslapyje. Tai nukreips naršyklę į /articles/new.

Tada testas užpildys straipsnio pavadinimo ir turinio laukus nurodytu tekstu. Užpildžius laukus, paspaudžiamas "Create Article", kuris sukurs naują straipsnį duomenų bazėje. Mes busime nukreipti atgal į straipsnių indekso puslapį ir ten patikrinsime, ar naujo straipsnio pavadinimo tekstas yra straipsnių indekso puslapyje.

6.3.2 Testavimas su keliais ekrano dydžiais

Jei norite testuoti mobilius dydžius kartu su staliniais dydžiais, galite sukurti kitą klasę, kuri paveldi iš ActionDispatch::SystemTestCase ir ją naudoti savo testų rinkinyje. Šiame pavyzdyje sukuriamas failas, vadinamas mobile_system_test_case.rb, kuris yra sukurtas /test kataloge su šia konfigūracija.

require "test_helper"

class MobileSystemTestCase < ActionDispatch::SystemTestCase
  driven_by :selenium, using: :chrome, screen_size: [375, 667]
end

Norėdami naudoti šią konfigūraciją, sukurkite testą test/system, kuris paveldi iš MobileSystemTestCase. Dabar galite testuoti savo programą naudodami kelias skirtingas konfigūracijas.

require "mobile_system_test_case"

class PostsTest < MobileSystemTestCase
  test "lankantis indekse" do
    visit posts_url
    assert_selector "h1", text: "Posts"
  end
end

6.3.3 Toliau eikime

Sistemos testavimo grožis yra tas, kad jis panašus į integracinį testavimą, kuris testuoja vartotojo sąveiką su jūsų valdikliu, modeliu ir rodiniu, bet sistemos testavimas yra daug patikimesnis ir iš tikrųjų testuoja jūsų programą taip, tarsi ją naudotų tikras vartotojas. Toliau galite testuoti bet ką, ką pats vartotojas darytų jūsų programoje, pvz., komentuoti, trinti straipsnius, publikuoti juodraščius ir t.t.

7 Integracinis testavimas

Integraciniai testai naudojami testuoti, kaip įvairios jūsų programos dalys sąveikauja. Jie dažniausiai naudojami testuoti svarbius darbo procesus jūsų programoje.

Kuriant integracinius testus „Rails“, naudojame test/integration katalogą savo programai. „Rails“ teikia generatorių, kuris sukurs mums integracinio testo pagrindo struktūrą.

$ bin/rails generate integration_test user_flows
      exists  test/integration/
      create  test/integration/user_flows_test.rb

Štai kaip atrodo naujai sugeneruotas integracinio testo pagrindas:

require "test_helper"

class UserFlowsTest < ActionDispatch::IntegrationTest
  # test "the truth" do
  #   assert true
  # end
end

Čia testas paveldi iš ActionDispatch::IntegrationTest. Tai suteikia mums papildomų pagalbinių funkcijų, kurias galime naudoti savo integraciniuose testuose.

7.1 Pagalbinės funkcijos, prieinamos integraciniams testams

Be įprastų testavimo pagalbinių funkcijų, paveldėjus iš ActionDispatch::IntegrationTest turime papildomų pagalbinių funkcijų, kurias galime naudoti rašydami integracinius testus. Trumpai susipažinkime su trimis pagalbinių funkcijų kategorijomis, iš kurių galime pasirinkti.

Norint dirbti su integracinio testo vykdytoju, žr. ActionDispatch::Integration::Runner.

Atliekant užklausas, turėsime ActionDispatch::Integration::RequestHelpers, kurias galime naudoti.

Jei reikia modifikuoti sesiją ar integracinio testo būseną, pažiūrėkite į ActionDispatch::Integration::Session.

7.2 Integracinio testo įgyvendinimas

Pridėkime integracinį testą į mūsų tinklaraščio programą. Pradėsime nuo pagrindinio darbo proceso, kuris apima naujo tinklaraščio straipsnio sukūrimą, kad patikrintume, ar viskas veikia tinkamai.

Pradėkime nuo integracinio testo pagrindo sugeneravimo:

$ bin/rails generate integration_test blog_flow

Turėtų būti sukurtas testo failo šablonas. Su ankstesniojo komandos rezultatu turėtume matyti:

      invoke  test_unit
      create    test/integration/blog_flow_test.rb

Dabar atidarykime tą failą ir parašykime pirmąjį tvirtinimą:

require "test_helper"

class BlogFlowTest < ActionDispatch::IntegrationTest
  test "can see the welcome page" do
    get "/"
    assert_select "h1", "Welcome#index"
  end
end

Pažiūrėsime į assert_select, kad užklaustume užklausos rezultato HTML „Testing Views“ skyriuje apačioje. Jis naudojamas testuoti mūsų užklausos atsaką, tvirtinant pagrindinių HTML elementų buvimą ir jų turinį.

Aplankydami šakninį kelias, turėtume matyti, kad welcome/index.html.erb yra atvaizduojamas rodinyje. Taigi šis tvirtinimas turėtų būti sėkmingas.

7.2.1 Straipsnių kūrimo integracija

Kaip dėl mūsų galimybės sukurti naują straipsnį savo tinklaraštyje ir pamatyti rezultatų straipsnį.

test "can create an article" do
  get "/articles/new"
  assert_response :success

  post "/articles",
    params: { article: { title: "can create", body: "article successfully." } }
  assert_response :redirect
  follow_redirect!
  assert_response :success
  assert_select "p", "Title:\n  can create"
end

Suskaidykime šį testą, kad galėtume jį suprasti.

Pradėkime nuo :new veiksmo iškvietimo mūsų Straipsniai valdiklyje. Šis atsakas turėtų būti sėkmingas.

Po to siunčiame POST užklausą į mūsų Straipsniai valdiklio :create veiksmą:

post "/articles",
  params: { article: { title: "can create", body: "article successfully." } }
assert_response :redirect
follow_redirect!

Dvi eilutės po užklausos skirtos tvarkyti peradresavimui, kurį nustatėme kuriant naują straipsnį.

PASTABA: Nepamirškite iškviesti follow_redirect!, jei planuojate atlikti kitas užklausas po peradresavimo.

Galiausiai galime patvirtinti, kad mūsų atsakas buvo sėkmingas ir naujas straipsnis yra matomas puslapyje.

7.2.2 Eiti toliau

Mums pavyko sėkmingai ištestuoti labai mažą darbo eigą, apsilankant mūsų tinklaraštyje ir kuriant naują straipsnį. Jei norėtume eiti toliau, galėtume pridėti testus komentarams, straipsnių šalinimui arba komentarų redagavimui. Integraciniai testai yra puiki vieta eksperimentuoti su visokiomis naudojimo atvejais mūsų programoms.

8 Funkciniai testai jūsų valdikliams

Rails aplinkoje valdiklių veiksmų testavimas yra funkcinių testų rašymo forma. Atsiminkite, kad jūsų valdikliai tvarko įeinančias interneto užklausas į jūsų programą ir galiausiai atsako su sugeneruota peržiūros forma. Rašydami funkcinius testus, jūs testuojate, kaip jūsų veiksmai tvarko užklausas ir tikėtiną rezultatą ar atsaką, kai kuriais atvejais tai yra HTML peržiūros forma.

8.1 Ką įtraukti į savo funkcinius testus

Turėtumėte testuoti tokius dalykus kaip:

  • ar interneto užklausa buvo sėkminga?
  • ar vartotojas buvo peradresuotas į tinkamą puslapį?
  • ar vartotojas sėkmingai autentifikuotas?
  • ar tinkamoje peržiūros formoje vartotojui buvo rodomas tinkamas pranešimas?
  • ar atsakyme buvo rodoma teisinga informacija?

Paprastiausias būdas pamatyti funkcinius testus veikime yra generuoti valdiklį naudojant scaffold generatorių:

$ bin/rails generate scaffold_controller article title:string body:text
...
create  app/controllers/articles_controller.rb
...
invoke  test_unit
create    test/controllers/articles_controller_test.rb
...

Tai sugeneruos valdiklio kodą ir testus Article resursui. Galite pažvelgti į failą articles_controller_test.rb test/controllers kataloge.

Jei jau turite valdiklį ir norite tik sugeneruoti testų struktūros kodą kiekvienam iš septynių numatytų veiksmų, galite naudoti šią komandą:

$ bin/rails generate test_unit:scaffold article
...
invoke  test_unit
create    test/controllers/articles_controller_test.rb
...

Pažvelkime į vieną tokių testų, test_should_get_index iš failo articles_controller_test.rb.

# articles_controller_test.rb
class ArticlesControllerTest < ActionDispatch::IntegrationTest
  test "should get index" do
    get articles_url
    assert_response :success
  end
end

test_should_get_index teste, Rails simuliuoja užklausą veiksmui, vadinamam index, įsitikindamas, kad užklausa buvo sėkminga ir taip pat užtikrina, kad buvo sugeneruota tinkama atsakymo forma.

get metodas paleidžia interneto užklausą ir rezultatus užpildo į @response. Jis gali priimti iki 6 argumentų:

  • Valdiklio veiksmo URI, kurį užklausiate. Tai gali būti eilutės arba maršruto pagalbininko (pvz., articles_url) forma.
  • params: parinktis su užklausos parametrų maišu, kurį perduoti veiksmui (pvz., užklausos eilutės parametrai arba straipsnio kintamieji).
  • headers: nustatant antraštės, kurios bus perduotos su užklausa.
  • env: tinkinamai pritaikant užklausos aplinką.
  • xhr: ar užklausa yra Ajax užklausa ar ne. Galima nustatyti true, jei norite pažymėti užklausą kaip Ajax.
  • as: užklausos kodavimui su skirtingu turinio tipu.

Visi šie raktiniai argumentai yra neprivalomi.

Pavyzdys: Iškviečiant pirmojo Article :show veiksmą ir perduodant HTTP_REFERER antraštę:

get article_url(Article.first), headers: { "HTTP_REFERER" => "http://example.com/home" }

Kitas pavyzdys: Iškviesti :update veiksmą paskutiniam Article, perduodant naują tekstą title params, kaip Ajax užklausa:

patch article_url(Article.last), params: { article: { title: "atnaujinta" } }, xhr: true

Dar vienas pavyzdys: Iškviesti :create veiksmą, kad sukurtum naują straipsnį, perduodant tekstą title params, kaip JSON užklausa:

post articles_path, params: { article: { title: "Ahoy!" } }, as: :json

PASTABA: Jei bandysite paleisti test_should_create_article testą iš articles_controller_test.rb, jis nepavyks dėl naujai pridėtos modelio lygio patikros ir tai yra teisinga.

Pakeiskime test_should_create_article testą articles_controller_test.rb, kad visi mūsų testai pavyktų:

test "should create article" do
  assert_difference("Article.count") do
    post articles_url, params: { article: { body: "Rails yra nuostabus!", title: "Sveiki Rails" } }
  end

  assert_redirected_to article_path(Article.last)
end

Dabar galite bandyti paleisti visus testus ir jie turėtų pavykti.

PASTABA: Jei sekėte žingsnius Pagrindinė autentifikacija skyriuje, jums reikės pridėti autorizaciją prie kiekvieno užklausos antraštės, kad visi testai pavyktų:

post articles_url, params: { article: { body: "Rails yra nuostabus!", title: "Sveiki Rails" } }, headers: { Authorization: ActionController::HttpAuthentication::Basic.encode_credentials("dhh", "secret") }

8.2 Galimi užklausų tipai funkciniuose testuose

Jei esate susipažinęs su HTTP protokolu, žinosite, kad get yra vienas iš užklausų tipų. Rails funkciniuose testuose yra palaikomi 6 užklausų tipai:

  • get
  • post
  • patch
  • put
  • head
  • delete

Visi užklausų tipai turi atitinkamus metodus, kuriuos galite naudoti. Tipiškoje C.R.U.D. aplikacijoje dažniau naudosite get, post, put ir delete.

PASTABA: Funkciniai testai neįsitikina, ar nurodytas užklausos tipas yra priimtas veiksmui, mums labiau rūpi rezultatas. Užklausų testai egzistuoja šiam tikslui, kad jūsų testai būtų tikslingesni.

8.3 Testuojant XHR (Ajax) užklausas

Norėdami testuoti Ajax užklausas, galite nurodyti xhr: true parinktį get, post, patch, put ir delete metodams. Pavyzdžiui:

test "ajax užklausa" do
  article = articles(:one)
  get article_url(article), xhr: true

  assert_equal "labas pasauli", @response.body
  assert_equal "text/javascript", @response.media_type
end

8.4 Trys Apokalipsės Hash'ai

Po to, kai užklausa yra padaryta ir apdorota, turėsite 3 Hash objektus, paruoštus naudoti:

  • cookies - Visi nustatyti slapukai
  • flash - Visi objektai, gyvenantys flash
  • session - Visi objektai, gyvenantys sesijos kintamuosiuose

Kaip ir su įprastais Hash objektais, galite pasiekti reikšmes, nurodydami raktus eilutėmis. Taip pat galite pasiekti jas pagal simbolio pavadinimą. Pavyzdžiui:

flash["gordon"]               flash[:gordon]
session["shmession"]          session[:shmession]
cookies["are_good_for_u"]     cookies[:are_good_for_u]

8.5 Prieinami objektai

Po užklausos padarymo, funkciniuose testuose taip pat turite prieigą prie trijų objektų:

  • @controller - Užklausą apdorojantis valdiklis
  • @request - Užklausos objektas
  • @response - Atsakymo objektas
class ArticlesControllerTest < ActionDispatch::IntegrationTest
  test "should get index" do
    get articles_url

    assert_equal "index", @controller.action_name
    assert_equal "application/x-www-form-urlencoded", @request.media_type
    assert_match "Straipsniai", @response.body
  end
end

8.6 Antraštės ir CGI kintamieji

HTTP antraštės ir CGI kintamieji gali būti perduodami kaip antraštės:

# nustatoma HTTP antraštė
get articles_url, headers: { "Content-Type": "text/plain" } # simuliuoti užklausą su pasirinkta antraštė

# nustatoma CGI kintamasis
get articles_url, headers: { "HTTP_REFERER": "http://example.com/home" } # simuliuoti užklausą su pasirinktu aplinkos kintamuoju

8.7 Testuojant flash pranešimus

Jei prisimenate iš ankstesnių skyrių, vienas iš Trijų Apokalipsės Hash'ų buvo flash.

Norime pridėti flash pranešimą į mūsų tinklaraščio aplikaciją, kai kas nors sėkmingai sukuria naują straipsnį.

Pradėkime pridėdami šią patikrą į mūsų test_should_create_article testą: ```ruby test "turėtų sukurti straipsnį" do assert_difference("Article.count") do post articles_url, params: { article: { title: "Koks nors pavadinimas" } } end

assert_redirected_to article_path(Article.last) assert_equal "Straipsnis buvo sėkmingai sukurtas.", flash[:notice] end ```

Jei dabar paleisime testą, turėtume pamatyti klaidą:

$ bin/rails test test/controllers/articles_controller_test.rb -n test_should_create_article
Run options: -n test_should_create_article --seed 32266

# Running:

F

Finished in 0.114870s, 8.7055 runs/s, 34.8220 assertions/s.

  1) Failure:
ArticlesControllerTest#test_should_create_article [/test/controllers/articles_controller_test.rb:16]:
--- expected
+++ actual
@@ -1 +1 @@
-"Article was successfully created."
+nil

1 runs, 4 assertions, 1 failures, 0 errors, 0 skips

Dabar įgyvendinkime "flash" pranešimą mūsų valdiklyje. Mūsų :create veiksmas turėtų atrodyti taip:

def create
  @article = Article.new(article_params)

  if @article.save
    flash[:notice] = "Straipsnis buvo sėkmingai sukurtas."
    redirect_to @article
  else
    render "new"
  end
end

Dabar, jei paleisime testus, turėtume matyti, kad jie sėkmingai įvyksta:

$ bin/rails test test/controllers/articles_controller_test.rb -n test_should_create_article
Run options: -n test_should_create_article --seed 18981

# Running:

.

Finished in 0.081972s, 12.1993 runs/s, 48.7972 assertions/s.

1 runs, 4 assertions, 0 failures, 0 errors, 0 skips

8.8 Viską sudedame kartu

Šiuo metu mūsų straipsnių valdiklis testuoja :index, :new ir :create veiksmus. Kaip dėl egzistuojančių duomenų tvarkymo?

Parašykime testą :show veiksmui:

test "turėtų rodyti straipsnį" do
  article = articles(:one)
  get article_url(article)
  assert_response :success
end

Atsiminkime iš ankstesnės diskusijos apie fiktyvius duomenis, kad articles() metodas suteiks mums prieigą prie mūsų straipsnių fiktyvių duomenų.

Kaip dėl egzistuojančio straipsnio ištrynimo?

test "turėtų ištrinti straipsnį" do
  article = articles(:one)
  assert_difference("Article.count", -1) do
    delete article_url(article)
  end

  assert_redirected_to articles_path
end

Taip pat galime pridėti testą egzistuojančio straipsnio atnaujinimui.

test "turėtų atnaujinti straipsnį" do
  article = articles(:one)

  patch article_url(article), params: { article: { title: "atnaujinta" } }

  assert_redirected_to article_path(article)
  # Atnaujintų duomenų gavimui ir patikrinimui, kad pavadinimas būtų atnaujintas, reikia perkrauti asociaciją.
  article.reload
  assert_equal "atnaujinta", article.title
end

Pastebėkite, kad pradedame matyti pasikartojimą šiuose trijuose testuose, jie visi naudoja tą patį straipsnio fiktyvų duomenų rinkinį. Galime sumažinti šį pasikartojimą naudodami setup ir teardown metodus, kurie yra pateikiami ActiveSupport::Callbacks.

Mūsų testas dabar turėtų atrodyti kaip šis. Kol kas praleiskime kitus testus, kad būtų trumpesnis kodas.

require "test_helper"

class ArticlesControllerTest < ActionDispatch::IntegrationTest
  # iškviečiamas prieš kiekvieną testą
  setup do
    @article = articles(:one)
  end

  # iškviečiamas po kiekvieno testo
  teardown do
    # jei valdiklis naudoja talpyklą, gali būti gerai ją išvalyti po to
    Rails.cache.clear
  end

  test "turėtų rodyti straipsnį" do
    # Perpanaudojame @article kintamąjį iš setup
    get article_url(@article)
    assert_response :success
  end

  test "turėtų ištrinti straipsnį" do
    assert_difference("Article.count", -1) do
      delete article_url(@article)
    end

    assert_redirected_to articles_path
  end

  test "turėtų atnaujinti straipsnį" do
    patch article_url(@article), params: { article: { title: "atnaujinta" } }

    assert_redirected_to article_path(@article)
    # Atnaujintų duomenų gavimui ir patikrinimui, kad pavadinimas būtų atnaujintas, reikia perkrauti asociaciją.
    @article.reload
    assert_equal "atnaujinta", @article.title
  end
end

Panašiai kaip ir kituose "Rails" kintamųjų, setup ir teardown metodus galima naudoti perduodant bloką, lambda arba metodo pavadinimą kaip simbolį.

8.9 Testavimo pagalbininkai

Norint išvengti kodo pasikartojimo, galite pridėti savo testavimo pagalbinius metodus. Pavyzdžiui, prisijungimo pagalbininkas gali būti geras pavyzdys:

# test/test_helper.rb

module SignInHelper
  def sign_in_as(user)
    post sign_in_url(email: user.email, password: user.password)
  end
end

class ActionDispatch::IntegrationTest
  include SignInHelper
end
require "test_helper"

class ProfileControllerTest < ActionDispatch::IntegrationTest
  test "turėtų rodyti profilį" do
    # pagalbinis metodas dabar gali būti naudojamas iš bet kurio valdiklio testo
    sign_in_as users(:david)

    get profile_url
    assert_response :success
  end
end

8.9.1 Naudojant atskirus failus

Jei pastebite, kad jūsų pagalbiniai metodai užkrauna test_helper.rb failą, galite juos išskaidyti į atskirus failus. Vienas geras vietos juos saugoti yra test/lib arba test/test_helpers. ```ruby

test/test_helpers/multiple_assertions.rb

module MultipleAssertions def assert_multiple_of_forty_two(number) assert (number % 42 == 0), "tikėtasi, kad #{number} bus daugiklis iš 42" end end ```

Šie pagalbininkai gali būti išreiškiamai reikalaujami ir įtraukiami, kaip reikia

require "test_helper"
require "test_helpers/multiple_assertions"

class NumberTest < ActiveSupport::TestCase
  include MultipleAssertions

  test "420 yra daugiklis iš keturiasdešimt du" do
    assert_multiple_of_forty_two 420
  end
end

arba jie gali toliau būti įtraukiami tiesiogiai į atitinkamas pagrindines klases

# test/test_helper.rb
require "test_helpers/sign_in_helper"

class ActionDispatch::IntegrationTest
  include SignInHelper
end

8.9.2 Greitai reikalaujant pagalbinių priemonių

Galite rasti patogu greitai reikalauti pagalbinių priemonių test_helper.rb, kad jūsų testų failai turėtų neaiškų prieigą prie jų. Tai galima padaryti naudojant globbing, kaip parodyta žemiau

# test/test_helper.rb
Dir[Rails.root.join("test", "test_helpers", "**", "*.rb")].each { |file| require file }

Tai turi trūkumą, kad padidėja paleidimo laikas, palyginti su rankiniu būdu reikalaujant tik reikalingų failų jūsų atskiruose testuose.

9 Maršrutų testavimas

Kaip ir viskas kitas jūsų „Rails“ programoje, galite testuoti savo maršrutus. Maršruto testai yra test/controllers/ aplanke arba yra dalis kontrolerio testų.

PASTABA: Jei jūsų programa turi sudėtingus maršrutus, „Rails“ teikia keletą naudingų pagalbinių priemonių jų testavimui.

Daugiau informacijos apie maršruto tikrinimo teiginius, kurie yra prieinami „Rails“, rasite API dokumentacijoje ActionDispatch::Assertions::RoutingAssertions.

10 Peržiūrėti testavimą

Testuojant atsaką į jūsų užklausą, patikrinant pagrindinių HTML elementų buvimą ir jų turinį, yra paprastas būdas testuoti jūsų programos rodinius. Kaip ir maršruto testai, peržiūros testai yra test/controllers/ aplanke arba yra dalis kontrolerio testų. assert_select metodas leidžia jums užklausti atsakos HTML elementus naudojant paprastą, tačiau galingą sintaksę.

Yra du assert_select formos:

assert_select(selector, [equality], [message]) užtikrina, kad pasirinktų elementų per selektorių būtų patenkinta lygybės sąlyga. Selektorius gali būti CSS selektoriaus išraiška (tekstas) arba išraiška su pakeitimo reikšmėmis.

assert_select(element, selector, [equality], [message]) užtikrina, kad pasirinktų elementų per selektorių būtų patenkinta lygybės sąlyga, pradedant nuo elemento („Nokogiri::XML::Node“ arba „Nokogiri::XML::NodeSet“) ir jo palikuonių.

Pavyzdžiui, galite patikrinti atsakos antraštės elemento turinį su:

assert_select "title", "Sveiki atvykę į „Rails“ testavimo vadovą"

Taip pat galite naudoti įdėtus assert_select blokus gilesniam tyrimui.

Šiame pavyzdyje vidinis assert_select blokas li.menu_item vykdomas viduje išorinio bloko pasirinktų elementų kolekcijos:

assert_select "ul.navigation" do
  assert_select "li.menu_item"
end

Pasirinktų elementų kolekcija gali būti peržiūrima, kad assert_select būtų galima atskirai iškviesti kiekvienam elementui.

Pavyzdžiui, jei atsakyme yra du surikiuoti sąrašai, kiekvienas su keturiais įdėtais sąrašo elementais, tada šie testai abu bus sėkmingi.

assert_select "ol" do |elements|
  elements.each do |element|
    assert_select element, "li", 4
  end
end

assert_select "ol" do
  assert_select "li", 8
end

Šis teiginys yra gana galingas. Daugiau pažangių naudojimo būdų rasite jo dokumentacijoje.

10.1 Papildomi rodinio pagrindu teiginiai

Yra daugiau teiginių, kurie daugiausia naudojami testuojant rodinius:

Teiginys Tikslas
assert_select_email Leidžia jums daryti teiginius el. laiško kūne.
assert_select_encoded Leidžia jums daryti teiginius užkoduotam HTML. Tai daroma atkoduojant kiekvieno elemento turinį ir tada kviečiant bloką su visais atkoduotais elementais.
css_select(selector) arba css_select(element, selector) Grąžina masyvą, kuriame yra visi selektoriaus pasirinkti elementai. Antrame variante jis pirmiausia atitinka pagrindinį elementą ir bando atitikti selektoriaus išraišką bet kuriam jo vaikui. Jei nėra atitikimų, abu variantai grąžina tuščią masyvą.

Štai pavyzdys, kaip naudoti assert_select_email:

assert_select_email do
  assert_select "small", "Norėdami atsisakyti, prašome paspausti „Atsisakyti prenumeratos“ nuorodą."
end

11 Testavimo pagalbininkai(fixed)

Pagalbininkas yra paprastas modulis, kuriame galite apibrėžti metodus, kurie yra prieinami jūsų rodiniuose.

Norėdami testuoti pagalbininkus, jums tereikia patikrinti, ar pagalbinio metodo išvestis atitinka tai, ką tikėtumėte. Pagalbininkų susiję testai yra išdėstyti test/helpers kataloge.

Turint šį pagalbininką:

module UsersHelper
  def link_to_user(user)
    link_to "#{user.first_name} #{user.last_name}", user
  end
end

Galime patikrinti šio metodo išvestį taip:

class UsersHelperTest < ActionView::TestCase
  test "should return the user's full name" do
    user = users(:david)

    assert_dom_equal %{<a href="/user/#{user.id}">David Heinemeier Hansson</a>}, link_to_user(user)
  end
end

Be to, kadangi testo klasė išplečia ActionView::TestCase, jūs turite prieigą prie „Rails“ pagalbinių metodų, tokių kaip link_to arba pluralize.

12 Pašto siuntėjų testavimas

Pašto siuntėjų klasės testavimui reikia tam tikrų specifinių įrankių, kad būtų atliktas kruopštus darbas.

12.1 Laikyti paštininką kontroliuojamą

Jūsų pašto siuntėjų klasės - kaip ir kiekviena kitą jūsų „Rails“ programos dalis - turėtų būti patikrintos, kad jos veiktų kaip tikėtasi.

Jūsų pašto siuntėjų klasės testavimo tikslai yra užtikrinti, kad:

  • elektroninės pašto žinutės būtų apdorojamos (sukuriamos ir siunčiamos)
  • elektroninės pašto žinutės turinys būtų teisingas (tema, siuntėjas, turinys ir kt.)
  • tinkamos elektroninės pašto žinutės būtų siunčiamos tinkamu laiku

12.1.1 Iš visų pusių

Yra du pašto siuntėjų testavimo aspektai: vienetų testai ir funkcinių testų. Vienetų testuose paleidžiate pašto siuntėją izoliacijoje su griežtai kontroliuojamais įvesties duomenimis ir palyginatį išvestį su žinoma reikšme (fiktyviu). Funkciniuose testuose jūs ne taip labai tikrinat pašto siuntėjo smulkmenas; vietoj to mes tikriname, ar mūsų valdikliai ir modeliai naudoja pašto siuntėją tinkamu būdu. Jūs testuojate, kad tinkama elektroninė pašto žinutė buvo išsiųsta tinkamu laiku.

12.2 Vienetų testavimas

Norėdami patikrinti, ar jūsų pašto siuntėjas veikia kaip tikėtasi, galite naudoti vienetų testus, kad palygintumėte pašto siuntėjo faktinį rezultatą su iš anksto parašytais pavyzdžiais.

12.2.1 Atkeršyti fiktyvams

Vienetų testavimui pašto siuntėjui naudojamos fiktyvios reikšmės, kurios pateikia pavyzdį, kaip turėtų atrodyti išvestis. Kadangi tai yra pavyzdinės elektroninės pašto žinutės, o ne aktyviosios įrašo duomenys, kaip kiti fiktyviniai duomenys, jos laikomos atskirame aplankale, atskirame nuo kitų fiktyvinių duomenų. Aplanko pavadinimas test/fixtures tiesiogiai atitinka pašto siuntėjo pavadinimą. Taigi, jei pašto siuntėjo pavadinimas yra UserMailer, fiktyviniai duomenys turėtų būti laikomi test/fixtures/user_mailer aplanke.

Jei sukūrėte savo pašto siuntėją, generatorius nesukuria fiktyvinių duomenų šablonų pašto siuntėjo veiksmams. Turėsite patys sukurti tuos failus, kaip aprašyta aukščiau.

12.2.2 Pagrindinė testo byla

Štai vienetų testas, skirtas patikrinti pašto siuntėją pavadinimu UserMailer, kurio veiksmas invite naudojamas siųsti pakvietimą draugui. Tai yra pritaikyta versija generatoriaus sukurtos pagrindinės testo, skirtos invite veiksmui.

require "test_helper"

class UserMailerTest < ActionMailer::TestCase
  test "invite" do
    # Sukurkite el. pašto žinutę ir ją saugokite tolimesniam tikrinimui
    email = UserMailer.create_invite("[email protected]",
                                     "[email protected]", Time.now)

    # Išsiųskite el. pašto žinutę, tada patikrinkite, ar ji buvo įtraukta į eilę
    assert_emails 1 do
      email.deliver_now
    end

    # Patikrinkite, ar išsiųstos el. pašto žinutės turinys atitinka tai, ką tikimės
    assert_equal ["[email protected]"], email.from
    assert_equal ["[email protected]"], email.to
    assert_equal "Jūs buvote pakviestas iš [email protected]", email.subject
    assert_equal read_fixture("invite").join, email.body.to_s
  end
end

Teste mes sukuriam el. pašto žinutę ir saugome grąžintą objektą kintamajame email. Tada užtikriname, kad ji buvo išsiųsta (pirmasis tikrinimas), tada, antrame tikrinime, užtikriname, kad el. pašto žinutė tikrai turi tai, ką tikimės. Pagalbinis metodas read_fixture naudojamas nuskaityti šio failo turinį. PASTABA: email.body.to_s yra naudojama, kai yra tik vienas (HTML arba tekstas) dalis. Jei pašto siuntėjas pateikia abu, galite savo fiktyvą išbandyti su konkrečiomis dalimis naudodami email.text_part.body.to_s arba email.html_part.body.to_s.

Čia yra invite fiktyvo turinys:

Sveikas [email protected],

Jūs buvote pakviestas.

Linkiu geros dienos!

Tai yra tinkamas laikas šiek tiek daugiau sužinoti apie testų rašymą savo pašto siuntėjams. Eilutė ActionMailer::Base.delivery_method = :test faile config/environments/test.rb nustato pristatymo būdą į testo režimą, todėl el. laiškai iš tikrųjų nebus išsiųsti (naudinga, norint išvengti vartotojų siunčiant šlamšto laiškus testuojant), o vietoj to jie bus pridėti prie masyvo (ActionMailer::Base.deliveries).

PASTABA: ActionMailer::Base.deliveries masyvas automatiškai nėra išvalomas ActionMailer::TestCase ir ActionDispatch::IntegrationTest testuose. Jei norite turėti švarų sąrašą už šių testų atvejų ribų, galite jį išvalyti rankiniu būdu naudodami: ActionMailer::Base.deliveries.clear

12.2.3 Išbandyti užsakytus el. laiškus

Galite naudoti assert_enqueued_email_with tvirtinimą, kad patvirtintumėte, jog el. laiškas buvo užsakytas su visais tikėtais pašto siuntėjo metodo argumentais ir/arba parametrizuotais pašto siuntėjo parametrais. Tai leidžia atitiktiems el. laiškams, kurie buvo užsakomi naudojant deliver_later metodą.

Kaip ir su pagrindiniu testo atveju, mes sukuriam el. laišką ir saugome grąžintą objektą kintamajame email. Šie pavyzdžiai apima argumentų ir/arba parametrų perdavimo variantus.

Šis pavyzdys patvirtins, kad el. laiškas buvo užsakytas su teisingais argumentais:

require "test_helper"

class UserMailerTest < ActionMailer::TestCase
  test "invite" do
    # Sukurkite el. laišką ir saugokite jį tolimesnėms tvirtinimams
    email = UserMailer.create_invite("[email protected]", "[email protected]")

    # Patikrinkite, ar el. laiškas buvo užsakytas su teisingais argumentais
    assert_enqueued_email_with UserMailer, :create_invite, args: ["[email protected]", "[email protected]"] do
      email.deliver_later
    end
  end
end

Šis pavyzdys patvirtins, kad pašto siuntėjas buvo užsakytas su teisingais pašto siuntėjo metodo vardinių argumentų pavadinimais, perduodant argumentų raktus kaip args:

require "test_helper"

class UserMailerTest < ActionMailer::TestCase
  test "invite" do
    # Sukurkite el. laišką ir saugokite jį tolimesnėms tvirtinimams
    email = UserMailer.create_invite(from: "[email protected]", to: "[email protected]")

    # Patikrinkite, ar el. laiškas buvo užsakytas su teisingais vardinių argumentų pavadinimais
    assert_enqueued_email_with UserMailer, :create_invite, args: [{ from: "[email protected]",
                                                                    to: "[email protected]" }] do
      email.deliver_later
    end
  end
end

Šis pavyzdys patvirtins, kad parametrizuotas pašto siuntėjas buvo užsakytas su teisingais parametrais ir argumentais. Pašto siuntėjo parametrai perduodami kaip params, o pašto siuntėjo metodo argumentai - kaip args:

require "test_helper"

class UserMailerTest < ActionMailer::TestCase
  test "invite" do
    # Sukurkite el. laišką ir saugokite jį tolimesnėms tvirtinimams
    email = UserMailer.with(all: "good").create_invite("[email protected]", "[email protected]")

    # Patikrinkite, ar el. laiškas buvo užsakytas su teisingais pašto siuntėjo parametrais ir argumentais
    assert_enqueued_email_with UserMailer, :create_invite, params: { all: "good" },
                                                           args: ["[email protected]", "[email protected]"] do
      email.deliver_later
    end
  end
end

Šis pavyzdys parodo alternatyvų būdą patikrinti, ar parametrizuotas pašto siuntėjas buvo užsakytas su teisingais parametrais:

require "test_helper"

class UserMailerTest < ActionMailer::TestCase
  test "invite" do
    # Sukurkite el. laišką ir saugokite jį tolimesnėms tvirtinimams
    email = UserMailer.with(to: "[email protected]").create_invite

    # Patikrinkite, ar el. laiškas buvo užsakytas su teisingais pašto siuntėjo parametrais
    assert_enqueued_email_with UserMailer.with(to: "[email protected]"), :create_invite do
      email.deliver_later
    end
  end
end

12.3 Funkcinis ir sisteminis testavimas

Vienetinis testavimas leidžia mums testuoti el. laiško atributus, o funkcinis ir sisteminis testavimas leidžia mums patikrinti, ar vartotojų sąveikos tinkamai sukelia el. laiško pristatymą. Pavyzdžiui, galite patikrinti, ar pakvietimo draugui operacija tinkamai siunčia el. laišką:

# Integracinis testas
require "test_helper"

class UsersControllerTest < ActionDispatch::IntegrationTest
  test "invite friend" do
    # Patvirtina skirtumą ActionMailer::Base.deliveries
    assert_emails 1 do
      post invite_friend_url, params: { email: "[email protected]" }
    end
  end
end
# Sisteminis testas
require "test_helper"

class UsersTest < ActionDispatch::SystemTestCase
  driven_by :selenium, using: :headless_chrome

  test "pakviesti draugą" do
    visit invite_users_url
    fill_in "El. paštas", with: "[email protected]"
    assert_emails 1 do
      click_on "Pakviesti"
    end
  end
end

PASTABA: assert_emails metodas nėra susietas su konkretaus pristatymo metodo ir veiks su elektroniniais laiškais, pristatomais naudojant deliver_now arba deliver_later metodą. Jei norime aiškiai patikrinti, ar laiškas buvo įtrauktas į eilę, galime naudoti assert_enqueued_email_with (pavyzdžiai aukščiau) arba assert_enqueued_emails metodus. Daugiau informacijos galima rasti dokumentacijoje čia.

13 Darbo testavimas

Kadangi jūsų adaptuoti darbai gali būti įtraukti į skirtingus jūsų programos lygius, jums reikės testuoti tiek patį darbą (jo elgesį, kai jis įtraukiamas į eilę), tiek ir kitus elementus, kurie jį teisingai įtraukia į eilę.

13.1 Pagrindinė testo atvejo

Pagal nutylėjimą, generuojant darbą, taip pat bus sugeneruotas susijęs testas pagal nutylėjimą esančiame test/jobs kataloge. Štai pavyzdinis testas su sąskaitos darbu:

require "test_helper"

class BillingJobTest < ActiveJob::TestCase
  test "that account is charged" do
    BillingJob.perform_now(account, product)
    assert account.reload.charged_for?(product)
  end
end

Šis testas yra gana paprastas ir tik patvirtina, kad darbas atliko tikėtą darbą.

13.2 Individualios patikros ir darbo testavimas kituose komponentuose

Active Job yra pritaikytas su daugybe individualių patikrų, kurios gali būti naudojamos testų mažinimui. Pilną galimų patikrų sąrašą rasite API dokumentacijoje ActiveJob::TestHelper.

Gera praktika užtikrinti, kad jūsų darbai būtų teisingai įtraukiami arba atliekami ten, kur juos iškviečiate (pvz., savo valdikliuose). Tai yra būtent ten, kur Active Job teikiamos individualios patikros yra labai naudingos. Pavyzdžiui, modelyje galite patvirtinti, kad darbas buvo įtrauktas:

require "test_helper"

class ProductTest < ActiveSupport::TestCase
  include ActiveJob::TestHelper

  test "billing job scheduling" do
    assert_enqueued_with(job: BillingJob) do
      product.charge(account)
    end
    assert_not account.reload.charged_for?(product)
  end
end

Numatytasis adapteris, :test, nevykdo darbų, kai jie yra įtraukiami į eilę. Turite jam pasakyti, kada norite, kad darbai būtų atlikti:

require "test_helper"

class ProductTest < ActiveSupport::TestCase
  include ActiveJob::TestHelper

  test "billing job scheduling" do
    perform_enqueued_jobs(only: BillingJob) do
      product.charge(account)
    end
    assert account.reload.charged_for?(product)
  end
end

Visi anksčiau atlikti ir įtraukti darbai yra išvalomi prieš bet kokį testą, todėl saugiai galite manyti, kad jokie darbai jau nebuvo vykdyti kiekviename testo kontekste.

14 Action Cable testavimas

Kadangi Action Cable naudojamas skirtinguose jūsų programos lygiuose, jums reikės testuoti tiek kanalus, ryšio klases patį, tiek ir kitus elementus, kurie transliuoja teisingus pranešimus.

14.1 Ryšio testo atvejis

Pagal nutylėjimą, generuojant naują Rails programą su Action Cable, taip pat bus sugeneruotas testas pagrindinei ryšio klasei (ApplicationCable::Connection) esančiam test/channels/application_cable kataloge.

Ryšio testai siekia patikrinti, ar ryšio identifikatoriai tinkamai priskiriami arba ar bet kokie netinkami ryšio užklausų yra atmetami. Štai pavyzdys:

class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
  test "connects with params" do
    # Simuliuojame ryšio atidarymą, iškviečiant `connect` metodą
    connect params: { user_id: 42 }

    # Ryšio objektą galite pasiekti per `connection` testuose
    assert_equal connection.user_id, "42"
  end

  test "rejects connection without params" do
    # Naudokite `assert_reject_connection` patikrinimą, kad
    # patvirtintumėte, kad ryšys yra atmestas
    assert_reject_connection { connect }
  end
end

Taip pat galite nurodyti užklausos slapukus taip pat, kaip tai darote integraciniuose testuose:

test "connects with cookies" do
  cookies.signed[:user_id] = "42"

  connect

  assert_equal connection.user_id, "42"
end

Daugiau informacijos rasite API dokumentacijoje ActionCable::Connection::TestCase.

14.2 Kanalo testo atvejis

Pagal nutylėjimą, generuojant kanalą, taip pat bus sugeneruotas susijęs testas pagal nutylėjimą esančiame test/channels kataloge. Štai pavyzdinis testas su pokalbių kanalu:

require "test_helper"

class ChatChannelTest < ActionCable::Channel::TestCase
  test "subscribes and stream for room" do
    # Simuliuojame prenumeratos sukūrimą, iškviečiant `subscribe`
    subscribe room: "15"

    # Kanalą galite pasiekti per `subscription` testuose
    assert subscription.confirmed?
    assert_has_stream "chat_15"
  end
end

Šis testas yra gana paprastas ir tik patvirtina, kad kanalas užsiprenumeruoja ryšį į konkretų srautą.

Taip pat galite nurodyti pagrindinius ryšio identifikatorius. Štai pavyzdinis testas su interneto pranešimų kanalu:

require "test_helper"

class WebNotificationsChannelTest < ActionCable::Channel::TestCase
  test "užsiprenumeruoja ir srautui naudotojui" do
    stub_connection current_user: users(:john)

    subscribe

    assert_has_stream_for users(:john)
  end
end

Daugiau informacijos rasite API dokumentacijoje ActionCable::Channel::TestCase.

14.3 Individualūs patvirtinimai ir transliacijų testavimas kituose komponentuose

Action Cable yra įdiegta su daugybe individualių patvirtinimų, kurie gali būti naudojami, norint sumažinti testų apimtį. Visą galimų patvirtinimų sąrašą rasite API dokumentacijoje ActionCable::TestHelper.

Gera praktika yra užtikrinti, kad teisingas pranešimas būtų transliuojamas kituose komponentuose (pvz., jūsų valdikliuose). Tai yra būtent ten, kur Action Cable teikiami individualūs patvirtinimai yra labai naudingi. Pavyzdžiui, modelyje:

require "test_helper"

class ProductTest < ActionCable::TestCase
  test "transliuojamas būsena po apmokejimo" do
    assert_broadcast_on("products:#{product.id}", type: "charged") do
      product.charge(account)
    end
  end
end

Jei norite patikrinti transliavimą, atliktą naudojant Channel.broadcast_to, turėtumėte naudoti Channel.broadcasting_for, kad generuotumėte pagrindinio srauto pavadinimą:

# app/jobs/chat_relay_job.rb
class ChatRelayJob < ApplicationJob
  def perform(room, message)
    ChatChannel.broadcast_to room, text: message
  end
end
# test/jobs/chat_relay_job_test.rb
require "test_helper"

class ChatRelayJobTest < ActiveJob::TestCase
  include ActionCable::TestHelper

  test "transliuojamas pranešimas į kambarį" do
    room = rooms(:all)

    assert_broadcast_on(ChatChannel.broadcasting_for(room), text: "Sveiki!") do
      ChatRelayJob.perform_now(room, "Sveiki!")
    end
  end
end

15 Eager Loading testavimas

Įprastai programos neaktyvuojamos development arba test aplinkose, kad pagreitintų veikimą. Tačiau jos aktyvuojamos production aplinkoje.

Jei dėl kokios nors priežasties projektas negali įkelti tam tikro failo, geriau tai nustatyti prieš diegiant į production, ar ne?

15.1 Nuolatinis integravimas

Jei jūsų projekte yra nuolatinis integravimas, aktyvusis įkėlimas CI yra paprastas būdas užtikrinti, kad programa būtų aktyvuojama.

Įprastai CI nustato tam tikrą aplinkos kintamąjį, nurodantį, kad testų rinkinys vykdomas ten. Pavyzdžiui, tai gali būti CI:

# config/environments/test.rb
config.eager_load = ENV["CI"].present?

Pradedant nuo Rails 7, naujai sukurtos programos yra konfigūruojamos pagal šį numatytąjį būdą.

15.2 Paprasti testų rinkiniai

Jei jūsų projekte nėra nuolatinio integravimo, vis tiek galite aktyvuoti programą testų rinkinyje, iškviesdami Rails.application.eager_load!:

15.2.1 Minitest

require "test_helper"

class ZeitwerkComplianceTest < ActiveSupport::TestCase
  test "aktyvuoja visus failus be klaidų" do
    assert_nothing_raised { Rails.application.eager_load! }
  end
end

15.2.2 RSpec

require "rails_helper"

RSpec.describe "Zeitwerk atitikimas" do
  it "aktyvuoja visus failus be klaidų" do
    expect { Rails.application.eager_load! }.not_to raise_error
  end
end

16 Papildomi testavimo ištekliai

16.1 Laiko priklausomo kodo testavimas

Rails teikia įmontuotas pagalbines metodus, kurie leidžia patikrinti, ar jūsų laiko priklausomas kodas veikia kaip tikėtasi.

Štai pavyzdys, naudojantis travel_to pagalbine:

# Tarkime, kad vartotojas gali dovanoti po mėnesio nuo registracijos.
user = User.create(name: "Gaurish", activation_date: Date.new(2004, 10, 24))
assert_not user.applicable_for_gifting?

travel_to Date.new(2004, 11, 24) do
  # Viduje `travel_to` bloko `Date.current` yra stubbed
  assert_equal Date.new(2004, 10, 24), user.activation_date
  assert user.applicable_for_gifting?
end

# Pakeitimas buvo matomas tik `travel_to` bloke.
assert_equal Date.new(2004, 10, 24), user.activation_date

Daugiau informacijos apie galimus laiko pagalbinius metodus rasite ActiveSupport::Testing::TimeHelpers API dokumentacijoje.

Atsiliepimai

Jūs esate skatinami padėti pagerinti šio vadovo kokybę.

Prašome prisidėti, jei pastebite rašybos klaidų ar faktinių klaidų. Norėdami pradėti, galite perskaityti mūsų dokumentacijos prisidėjimo skyrių.

Taip pat gali būti nepilnos informacijos arba informacijos, kuri nėra atnaujinta. Prašome pridėti bet kokią trūkstamą dokumentaciją pagrindiniam. Patikrinkite Edge vadovus pirmiausia, ar problemas jau išspręsta arba ne pagrindinėje šakoje. Patikrinkite Ruby on Rails vadovų gaires dėl stiliaus ir konvencijų.

Jei dėl kokios nors priežasties pastebite kažką, ką reikia ištaisyti, bet negalite patys tai pataisyti, prašome pranešti apie problemą.

Ir galiausiai, bet ne mažiau svarbu, bet koks diskusijos dėl Ruby on Rails dokumentacijos yra labai laukiamos oficialiame Ruby on Rails forume.