Rubyn send-metodi auttaa tiivistämään testikoodia

Kirjoitettu

Kuvitellaan että meillä on sovellus, jonka yksi tietomalli on lasku. Laskussa on tyypillisesti useita eri kenttiä, joiden kaikkien toiminta täytyy testata mallin yksikkötesteissä. Malli ei esimerkiksi saa hyväksyä tyhiä arvoja pakollisiin kenttiin.

Yksi vaihtoehto on kirjoittaa oma testi jokaisen kentän testaukselle:

test "invalid invoice if iban is empty or nill" do
    @invoice.iban = ""
    assert !@invoice.valid?
    @invoice.iban = nil
    assert !@invoice.valid?
end

test "invalid invoice if due date is empty or nill" do
    @invoice.due_date = ""
    assert !@invoice.valid?
    @invoice.due_date = nil
    assert !@invoice.valid?
end

...

Mutta jos testattavia kenttiä on paljon, on tämä tapa tarpeettoman työläs johtaa lähes identtisen koodin toistamiseen.

Rubyssä on kuitenkin näppärä ominaisuus, jonka avulla testit voidaan kirjoittaa tiiviimpää muotoon.

send on Object-luokan metodi, joka yksinkertaisesti kutsuu sille parametrina annettavaa metodia. Normaalikäytössä tämä on aika tarpeeton toiminto – helpointa on vain kutsua haluttua metodia suoraan kierrättämättä kutsua sendin kautta. Mutta jos haluttu metodi onkin muuttuja, on send tarpeellinen apukeino.

Nyt testikoodi voidaan kirjoittaa tiiviiseen ja toistoa välttävään muotoon:

test "invalid invoice if mandatory fields are empty" do
    @invoice = invoices(:one)
    [
        "receiver_name",
        "receiver_email",
        "receiver_address",
        "receiver_tax_id",
        "sender_name",
        "sender_email",
        "sender_address",
        "sender_tax_id",
        "iban",
        "bic",
        "delivery_method",
        "bill_number",
        "reference",
        "status",
        "issue_date",
        "due_date"
    ].each do |key|
        invoice = @invoice.dup
        invoice.send "#{key}=", ""
        assert !invoice.valid?
        invoice.send "#{key}=", nil
        assert !invoice.valid?
    end
end

Tällä tavalla voidaan ensin muodostaa lista halutuista kentistä, joille kutsutaan yhtä ja samaa koodilohkoa, joka tekee varsinaisen testauksen.

Yllä olevassa esimerkissä kentän nimi saapuu lohkolle key-muuttujassa. Koska send hyväksyy parametrinaan symbolin lisäksi myös merkkijonon, voidaan käyttää merkkijojon interpolointia eli #{}-syntaksia lisäämään =-merkki parametrin perään. Tämä puolestaan liittyy Rails-frameworkin ominaisuuteen – jokaisella tietomallin kentällä on automaattisesti setter-metodi. Jos siis kentän nimi on foo, on sitä vastaava setter-metodi foo=.

Jälkimmäinen send-metodin parametreista on kentälle asetettava arvo. Tässä tapauksessa haluamme testata sekä tyhjän merkkijonon että nil-arvon.

Heti lohkon alussa oleva olion kopiointi dup-metodilla tehdään puolestaan siksi, jotta käytössä on tuore invoice-olio, jonka alkuarvot ovat joka testauskierroksella samat.

Lopputuloksena on entistä tiiviimpi, kauniimpi ja helpommin ylläpidettävä katkelma koodia.