Matteo Manferdini

Monien kehittäjien mielestä yksikkötestaus on hämmentävää. Tätä pahentavat kehittyneet tekniikat, joita tarvitaan luokkien tai asynkronisen koodin, kuten verkkopyyntöjen, testaamiseen.

Todellisuudessa yksikkötestauksen pohjalla ovat yksinkertaiset peruskäsitteet. Kun ne ymmärtää, yksikkötestauksesta tulee yhtäkkiä helpommin lähestyttävää.

Sisältö

  • Yksikkötestauksen selittäminen yksinkertaisesti, ymmärrettävin termein
  • Yksikkötestauksen avulla voit tarkistaa vaikeasti saavutettavat ääritapaukset ja ehkäistä virheitä
  • Yksikkötestien kirjoittaminen Xcodessa
  • Hyvä arkkitehtuuri helpottaa koodin testaamista
  • Arvotyyppien käsitteleminen puhtaina funktioina yksikkötestauksen yksinkertaistamiseksi
  • Koodisi varmentaminen XCTest-kehyksen assertions-funktioiden avulla
  • Testin koodin kattavuuden mittaaminen Xcodessa
  • Miksi tietyn koodin kattavuuden tavoittelu on turhaa ja mitä sen sijaan kannattaa tehdä

Yksikkötestaus selitettynä yksinkertaisesti, ymmärrettävin termein

Kun kirjoitat sovellusta, käyt läpi syklin, jossa kirjoitat koodia, suoritat sen ja tarkistat, toimiiko se tarkoitetulla tavalla. Mutta kun koodisi kasvaa, koko sovelluksen testaaminen manuaalisesti käy vaikeammaksi.

Automaattinen testaus voi suorittaa nämä testit puolestasi. Käytännössä yksikkötestaus on siis koodia, jolla varmistetaan, että sovelluksesi koodi on oikein.

Toinen syy siihen, miksi yksikkötestausta voi olla vaikea ymmärtää, on se, että sen ympärillä on monia käsitteitä: testaaminen Xcodessa, sovelluksen arkkitehtuuri, testikaksoset, riippuvuusinjektio ja niin edelleen.

Yksikkötestauksen ajatus on kuitenkin ytimeltään melko suoraviivainen. Voit kirjoittaa yksinkertaisia yksikkötestejä tavallisella Swiftillä. Et tarvitse mitään erityistä Xcode-ominaisuutta tai hienostunutta tekniikkaa, ja voit jopa ajaa niitä Swift Playgroundin sisällä.

Katsotaanpa esimerkkiä. Alla oleva funktio laskee kokonaisluvun faktoriaalin, joka on kaikkien positiivisten kokonaislukujen tulo, jotka ovat pienempiä tai yhtä suuria kuin syöte. Int) -> Int {

var result = 1
for factor in 1…number {
result = result * factor
}
return result
}

Testataksesi tätä funktiota manuaalisesti, syötät sille pari lukua ja tarkistat, että tulos on se mitä odotat. Kokeilisit sitä esimerkiksi luvulla neljä ja tarkistaisit, että tulos on 24.

Voit automatisoida tämän kirjoittamalla Swift-funktion, joka tekee testin puolestasi. = 24 {

print(”Factorial of 3 on väärä”)

} }
}

Tämä on yksinkertaista Swift-koodia, jonka jokainen ymmärtää. Se vain tarkistaa funktion tulosteen ja tulostaa viestin, jos se ei ole oikein.

Se on yksikkötestaus pähkinänkuoressa. Kaikki muu on Xcoden lisäämiä kelloja ja pillejä, joiden tarkoituksena on tehdä testauksesta yksinkertaisempaa.

Tai näin ainakin olisi, jos sovelluksiemme koodi olisi yhtä yksinkertaista kuin juuri kirjoittamamme faktorifunktio. Siksi tarvitset Xcoden tukea ja kehittyneitä tekniikoita, kuten testituplauksia.

Tästä huolimatta tämä ajatus on hyödyllinen sekä yksinkertaisille että monimutkaisille testeille.

Yksikkötestauksen avulla voit tarkastaa vaikeasti saavutettavat ääritapaukset ja ehkäistä virheitä

Yksikkötestauksesta saat useita hyötyjä.

Yksikkötestauksesta ilmeisin on se, että sinun ei tarvitse testata koodiasi jatkuvasti käsin. Voi olla työlästä ajaa sovelluksesi ja päästä tiettyyn paikkaan, jossa on toiminnallisuus, jota haluat testata.

Mutta siinä ei ole vielä kaikki. Yksikkötestien avulla voit myös testata ääritapauksia, joita saattaa olla vaikea luoda käynnissä olevassa sovelluksessa. Ja ääritapaukset ovat se paikka, jossa useimmat virheet elävät.

Mitä tapahtuu esimerkiksi, jos syötämme nollaa tai negatiivista lukua edellä mainittuun factorial(of:)-funktioomme?

1
2
3
4
4
5

func testFaktoriaaliNollasta() {
if faktoriaali(of: 0) != 1 {
print(”Factorial of 0 on väärä”)
} }
}

Koodimme hajoaa:

Oikeassa sovelluksessa tämä koodi aiheuttaisi kaatumisen. Nolla on for-silmukassa alueen ulkopuolella.

Mutta koodimme ei kaadu Swiftin alueiden rajoituksen takia. Se epäonnistuu, koska unohdimme ottaa koodissamme huomioon ei-positiiviset kokonaisluvut. Määritelmän mukaan negatiivisen kokonaisluvun faktoriaalia ei ole olemassa, kun taas 0:n faktoriaali on 1.

13
13
func factorial(of number: Int) -> Int? {
if (luku < 0) {
return nil
} }
if (luku == 0) {
return 1
} }
var result = 1
for factor in 1…number {
result = result * factor
}
return result
}

Voitamme nyt suorittaa testimme uudelleen ja lisätä vielä tarkistuksen negatiivisille luvuille.

1
2
3
4
4
5

func testFaktoriaaliNegatiivisenIntegerinLaskennassa() {
if faktoriaali(of: -1) != nil {
print(”Faktoriaali -1:stä on väärä”)
}
}

Tässä näet yksikkötestauksen viimeisen ja mielestäni tärkeimmän hyödyn. Aiemmin kirjoittamamme testit varmistavat, että kun päivitämme factorial(of:)-funktiota, emme riko sen olemassa olevaa koodia.

Tämä on ratkaisevan tärkeää monimutkaisissa sovelluksissa, joissa joudutaan jatkuvasti lisäämään, päivittämään ja poistamaan koodia. Yksikkötestaus antaa sinulle varmuuden siitä, että muutoksesi eivät rikkoneet hyvin toiminutta koodia.

Yksikkötestien kirjoittaminen Xcodessa

Yksikkötestien ymmärtämisen myötä voimme nyt tarkastella Xcoden testausominaisuuksia.

Luoessasi uuden Xcode-projektin saat mahdollisuuden lisätä yksikkötestauksen heti. Käytän esimerkkinä sovellusta, jolla seurataan kaloreita. Löydät koko Xcode-projektin täältä.

Kun valitset tämän vaihtoehdon, malliprojektisi sisältää jo valmiiksi määritetyn testikohteen. Voit aina lisätä sellaisen myöhemmin, mutta minä yleensä tarkistan vaihtoehdon oletusarvoisesti. Vaikka en aikoisikaan kirjoittaa testejä heti, kaikki on valmiina, kun päätän tehdä niin.

Testikohteessa on jo valmiiksi jonkin verran mallikoodia testejämme varten.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

import XCTest
@testable import Kalorimet
class Kalorimetritestit: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. Tätä metodia kutsutaan ennen luokan jokaisen testimetodin kutsumista.
}
override func tearDownWithError() throws {
// Laita teardown-koodi tähän. Tätä metodia kutsutaan luokan jokaisen testimetodin kutsumisen jälkeen.
}
func testExample() throws {
// Tämä on esimerkki toiminnallisesta testitapauksesta.
// Käytä XCTAssertia ja siihen liittyviä funktioita varmistaaksesi, että testit tuottavat oikeat tulokset.
}
func testPerformanceExample() throws {
// Tämä on esimerkki suorituskykytestitapauksesta.
self.measure {
// Laita tähän koodi, jonka aikaa haluat mitata.
}
}
}

  • Rivi @testable import Calories antaa sinulle pääsyn kaikkiin tyyppeihin projektisi pääkohteessa. Swift-moduulin koodiin ei pääse käsiksi ulkopuolelta, ellei kaikkia tyyppejä ja metodeja ole nimenomaisesti ilmoitettu julkisiksi. Avainsanan @testable avulla voit kiertää tämän rajoituksen ja päästä käsiksi jopa yksityiseen koodiin.
  • Luokka CaloriesTests edustaa testitapausta eli toisiinsa liittyvien testien ryhmittymää. Testitapausluokan täytyy polveutua XCTestCase-luokasta.
  • Metodin setUpWithError() avulla voit asettaa vakioympäristön kaikille testitapauksen testeille. Jos sinun täytyy tehdä siivouksia testien jälkeen, käytät tearDownWithError()-metodia. Nämä metodit suoritetaan ennen ja jälkeen jokaisen testitapauksen testin. Emme tarvitse niitä, joten voit poistaa ne.
  • Metodi testExample() on samanlainen testi kuin ne, jotka kirjoitimme factorial-esimerkkiämme varten. Voit nimetä testimetodit haluamallasi tavalla, mutta niiden täytyy alkaa test-etuliitteellä, jotta Xcode tunnistaa ne.
  • Ja lopuksi testPerformanceExample() näyttää, miten voit mitata koodisi suorituskykyä. Suorituskykytestit eivät ole yhtä vakiomuotoisia kuin yksikkötestit, ja käytät niitä vain kriittiseen koodiin, jonka täytyy olla nopeaa. Emme myöskään käytä tätä menetelmää.

Kaikki testitapaukset ja suhteelliset testit löytyvät listattuna Xcoden Test-navigaattorista.

Voit lisätä projektiin uusia testitapauksia luomalla yksinkertaisesti uuden .swift-tiedostoja, joissa on yllä olevan kaltaista koodia, mutta on helpompaa käyttää Testinavigaattorin alareunassa olevaa Lisää-valikkoa.

Hyvä arkkitehtuuri helpottaa koodin testaamista

Todellisessa projektissa ei yleensä ole irrallisia funktioita, kuten esimerkissämme factorial. Sen sijaan sinulla on rakenteita, luetteloita ja luokkia, jotka edustavat sovelluksesi eri osia.

On ratkaisevan tärkeää organisoida koodisi MVC:n tai MVVM:n kaltaisen suunnittelumallin mukaisesti. Hyvin jäsennelty koodi ei ainoastaan tee koodistasi hyvin organisoitua ja helpommin ylläpidettävää. Se myös helpottaa yksikkötestausta.

Tämä auttaa meitä myös vastaamaan yleiseen kysymykseen: mitä koodia sinun pitäisi testata ensin?

Vastaus on: aloita mallityypeistäsi.

Tälle on useita syitä:

  • Jos noudatat MVC-mallia tai jotakin sen johdannaismallia, mallityyppisi sisältävät toimialueen toimintalogiikan. Koko sovelluksesi riippuu tällaisen koodin oikeellisuudesta, joten muutamalla testilläkin on merkittävä vaikutus.
  • Mallityypit ovat usein rakenteita, jotka ovat arvotyyppejä. Näitä on paljon helpompi testata kuin viittaustyyppejä (näemme kohta miksi).
  • Viittaustyypeillä eli luokilla on riippuvuuksia ja ne aiheuttavat sivuvaikutuksia. Niiden yksikkötestien kirjoittamiseen tarvitaan testikaksosia (dummies, stubs, fakes, spies ja mocks) ja käytetään hienostuneita tekniikoita.
  • Valvojat (MVC-termeissä) tai näkymämallit (MVVM-termeissä) ovat usein yhteydessä resursseihin, kuten levytallennustilaan, tietokantaan, verkkoon ja laiteantureihin. Ne saattavat myös suorittaa rinnakkaista koodia. Nämä vaikeuttavat yksikkötestausta.
  • Näkymäkoodi muuttuu useimmin, mikä tuottaa hauraita testejä, jotka rikkoutuvat helposti. Eikä kukaan halua korjata rikkinäisiä testejä.

Käsitellään arvotyyppejä puhtaina funktioina yksikkötestauksen yksinkertaistamiseksi

Lisätään siis sovellukseemme joitakin mallityyppejä.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

struct ElintarvikeItimen {
let name: String
let caloriesFor100Grams: Int
let grams: Int
}
struct Meal {
private(set) var items: =
var calories: Int {
var calories = 0
for item in items {
calories += (item.caloriesFor100Grams / 100) * item.grams
}
return calories
} }
mutating func add(_ item: FoodItem) {
items.append(item)
}
}

Rakenne Meal sisältää yksinkertaisen logiikan, jolla lisätään ruoka-aineksia ja lasketaan sen sisältämien ruokien kokonaiskalorit.

Yksikkötestauksella on tällainen nimi, koska koodia kannattaa testata erillisinä yksikköinä, jolloin kaikki riippuvuudet poistetaan (riippuvuuksien testaamista yhdessä kutsutaan sen sijaan integrointitestaukseksi). Jokaista yksikköä käsitellään tällöin mustana laatikkona. Syötät sille jotain syötettä ja testaat sen tuotoksen tarkistaaksesi, onko se sitä, mitä odotat.

Tämä oli helppoa esimerkkimme factorialin tapauksessa, koska se oli puhdas funktio, eli funktio, jonka tuotos riippuu vain syötteestä, eikä se aiheuta mitään sivuvaikutuksia.

Mutta näin ei näytä olevan Meal-tyypissämme, joka sisältää tilaa.

Tilaa sisältävällä Calories-ominaisuudellamme ei ole syötettä. Se riippuu vain items-määrän sisällöstä. Metodi add(_:) sen sijaan ei palauta mitään arvoa ja muuttaa vain aterian sisäistä tilaa.

Mutta rakenteet ovat arvotyyppejä, ja voimme pitää niitä puhtaina funktioina. Koska niillä ei ole riippuvuuksia, voit pitää rakenteen alkutilaa metodin syötteenä ja metodin kutsun jälkeistä tilaa metodin ulostulona.

(Tämä on yksi syy siihen, miksi viitetyyppien asettamista arvotyyppien sisälle kannattaa välttää).

Koodin tarkistaminen XCTest-kehyksen assertions-funktioiden avulla

Meillä on nyt koodia testattavaksi ja Xcode-projektissamme paikka, johon testit kirjoitetaan.

Meiltä puuttuu vielä viimeinen ainesosa: keino ilmaista, onko koodimme oikein vai ei.

Tämän artikkelin alussa olleessa esimerkissä käytin yksinkertaisia print-lauseita. Se ei ole käytännöllistä todellisessa yksikkötestauksessa. Et halua tuhlata aikaa lokien läpikäyntiin sen selvittämiseksi, mitkä testit epäonnistuivat. Tarvitsemme keinon, joka osoittaa suoraan epäonnistuneisiin testeihin.

XCTest-kehyksestä löytyy joukko väittämisfunktioita, jotka saavat Xcoden osoittamaan testeihin, jotka eivät läpäise.

Näiden avulla voimme kirjoittaa ensimmäisen testimme.

Kuten edellä mainitsin, yksikkötesteistä on apua ääritapausten tarkistamisessa, joten aletaan varmistaa, että tyhjässä ateriassa ei ole kaloreita. XCTestCase {

func testEmptyMeal() throws {
let meal = Meal()
XCTAssertEqual(meal.calories, 0, ”Tyhjällä aterialla pitäisi olla 0 kaloria”)
}
}

XCTest tarjoaa yleisen XCTAssert-funktion, jonka avulla voit vakuuttaa minkä tahansa ehdon. Voit käyttää sitä mihin tahansa kirjoittamaasi testiin, mutta on parempi käyttää mahdollisuuksien mukaan erikoistuneempia väittämisfunktioita, kuten XCTAssertEqual (yllä), XCTAssertNil ja muita. Nämä tuottavat Xcodessa parempia virheitä kuin XCTAssert.

Voit suorittaa yksittäisen testin klikkaamalla sen nimen vieressä olevaa timanttia koodieditorin kourussa.

Kun testi läpäisee testin, se muuttuu vihreäksi, kun taas epäonnistuneet testit merkitään punaisella. Voit vaihtaa testissä olevan 0:n mihin tahansa muuhun numeroon nähdäksesi, miltä epäonnistunut testi näyttää.

Voit suorittaa kaikki testit testitapauksessa klikkaamalla luokan julistuksen vieressä olevaa timanttia. Voit myös käyttää edellä näkemäämme Test-navigaattoria yksittäisten testien tai testitapausten suorittamiseen.

Haluat usein suorittaa kaikki projektin testit kerralla, minkä voit tehdä nopeasti painamalla näppäimistöllä cmd+U tai valitsemalla Xcoden tuotevalikosta Test-vaihtoehdon.

Testin koodin kattavuuden mittaaminen Xcodessa

Yksikkötestaukseen liittyvä seuraava, yleisin kysymys on: Kuinka paljon koodistasi kannattaa testata?

Tätäkin mitataan yleensä koodin kattavuudella, ts, prosenttiosuus koodista, jonka testisi kattavat. Ennen kuin siis vastaamme tähän kysymykseen, katsotaan, miten voit mitata testiesi koodin kattavuutta Xcodessa.

Aluksi sinun on annettava Xcoden kerätä kattavuus testikohteellesi. Napsauta Xcoden työkalupalkin segmentoidussa ohjaimessa olevaa painiketta, jossa on projektin nimi (pysäytyspainikkeen vieressä). Valitse sitten ponnahdusvalikosta Muokkaa järjestelmää….

Valitse siellä ääriviivasta Testi ja siirry sitten Asetukset-välilehdelle. Ja lopuksi valitse Gather coverage for. Voit jättää sen vaihtoehdon kaikki kohteet.

Voit nyt suorittaa testit uudelleen, jolloin Xcode voi kerätä kattavuustiedot. Löydät tuloksen Raportti-navigaattorista valitsemalla Koodin kattavuus -kohdan hahmotelmasta.

Tässä voit tarkistaa testiesi kattaman koodin prosentuaaliset osuudet koko projektissa ja jokaisessa tiedostossa.

Nämä luvut eivät ole esimerkkimme kannalta kovin merkittäviä, sillä emme kirjoittaneet juurikaan koodia. Voimme silti nähdä, että Meal-tyypin add(_:)-metodilla on 0 %:n kattavuus, mikä tarkoittaa, ettemme ole testanneet sitä vielä.

Calories computed -ominaisuudella on sen sijaan 85,7 %:n kattavuus, mikä tarkoittaa, että koodissamme on joitain suorituspolkuja, joita testimme eivät laukaisseet.

Yksinkertaisessa esimerkissämme on helppo ymmärtää, mikä polku tuo on. Testasimme vain tyhjän aterian kaloreita, joten for-silmukassa olevaa koodia ei suoritettu.

Hienostuneemmissa menetelmissä se ei kuitenkaan välttämättä ole yhtä suoraviivaista.

Sitä varten voit tuoda koodin kattavuuskaistaleen esiin Xcode-editorissa. Löydät sen oikeassa yläkulmassa olevasta Adjust Editor Options -valikosta.

Tällöin esiin tulee liuska, joka näyttää kunkin koodirivin kattavuuden.

Numerot kertovat, kuinka monta kertaa kutakin riviä suoritettiin testauksen aikana. Punaisella näet, mitä rivejä ei suoritettu lainkaan (täysi) tai suoritettiin vain osittain (raidallinen).

Miksi tietyn koodin kattavuuden tavoittelu on merkityksetöntä ja mitä sen sijaan pitäisi tehdä

Mitkä prosenttiluvut ovat hyvä koodin kattavuusprosentti?

Mielipiteet vaihtelevat suuresti. Joidenkin kehittäjien mielestä 20 % riittää. Toiset pyrkivät korkeampiin lukuihin, kuten 70 tai 80 prosenttiin. On jopa kehittäjiä, joiden mielestä vain 100 % on hyväksyttävä.

Minusta koodin kattavuus on merkityksetön mittari. Sitä voi käyttää päätöksenteon pohjana testausta koskevissa päätöksissä, mutta sitä ei pidä käsitellä tavoitteena, johon on päästävä.

Katsoaksemme miksi, kirjoitetaan toinen testi kattamaan koodi, jota emme ole vielä testanneet. XCTestCase {

let banana = FoodItem(name: ”Banaani”, caloriesFor100Grams: 89, grams: 118)
let steak = FoodItem(name: ”Pihvi”, caloriesFor100Grams: 271, grams: 225)
let goatCheese = FoodItem(name: ”Goat Cheese”, caloriesFor100Grams: 364, grams: 28)
func testEmptyMeal() throws {
let meal = Meal()
XCTAssertEqual(meal.calories, 0, ”Tyhjällä aterialla pitäisi olla 0 kaloria”)
}
func testCalories() {
var meal = Meal()
meal.add(banaani)
meal.add(pihvi)
meal.add(vuohenjuusto)
XCTAssertEqual(meal.items.count, 3)
XCTAssertEqual(meal.calories, 534)
} }
}

Jos kaikki testit ajetaan uudelleen, Model.swift-tiedoston kattavuus on 100 %. Näyttää hyvältä, eikö?

Mene nyt ja poista testEmptyMeal()-metodi. Jos suoritat jäljelle jääneet testit yksin, huomaat, että Meal-tyyppiemme kattavuus on edelleen 100 %.

Tämä osoittaa jo nyt, että 100 %:n luku voi antaa väärän turvallisuuden tunteen. Tiedät, että nyt emme testaa kaikkia lasketun kalorit-ominaisuuden ääritapauksia. Silti testikattavuutemme ei heijasta sitä.

Lisään vielä, että 100 %:n kattavuus ei ole vain harhaanjohtava vaan jopa haitallinen. Osa projektin koodista on altista jatkuville muutoksille, erityisesti uusin koodi ja erityisesti näkymät.

100 %:n kattavuus tarkoittaa, että joudut vain tuottamaan hauraita testejä, jotka rikkoutuvat jatkuvasti ja joudut korjaamaan. Nämä testit eivät havaitse bugeja. Ne rikkoutuvat, koska koodisi toiminnallisuus muuttuu.

Ja tässä päästään kohtaan, josta kukaan ei puhu.

Testien kirjoittaminen ei ole hauskaa, vaikka jotkut kehittäjät niin väittävätkin. Testien korjaaminen on vielä vähemmän hauskaa. Jos teet sitä liikaa, vihaat yksikkötestausta ja työnnät sen kokonaan syrjään.

Psykologia on ohjelmistokehityksessä yhtä tärkeää kuin parhaat käytännöt. Me emme ole koneita.

Mihin numeroon kannattaa siis pyrkiä? Se vaatii laajemman keskustelun, mutta tässä annan yhteenvedon mielipiteestäni.

Kirjoita hyödyllisiä testejä alkaen projektisi vanhimmasta koodista, joka ei tule muuttumaan. Käytä koodin kattavuutta vain tunnistamaan, mitä koodia ei ole vielä testattu, mutta älä käytä sitä tavoitteena tai päättämään, milloin kannattaa kirjoittaa lisää testejä. 20 %:n kattavuus on parempi kuin 80 %, jos testit ovat mielekkäitä ja testaat oikeaa koodia.

Kuten edellä mainitsin, mallityypit sisältävät projektin kriittisintä koodia, joka myös yleensä muuttuu vähiten. Aloita siis siitä.

En yleensä vaivaudu testaamaan jokaista suorituspolkua. Esimerkiksi oikeassa projektissa en kirjoittaisi edellä näyttämääni testEmptyMeal()-metodia. Kyllä, ääritapausten testaaminen on tärkeää, mutta ne eivät ole kaikki tärkeitä.

Kirjoittaisin tyypillisesti vain testCalories()-testin. Se kertoo minulle, että koodini toimii, ja se varoittaa minua, jos myöhemmin teen virheen muuttaessani tätä metodia.

Totta kai se ei kata kaikkia polkuja, mutta tämä koodi on niin yksinkertaista, että se on vain ajanhukkaa. Ajan käyttäminen todellisen koodin kirjoittamiseen ominaisuuksia varten, jotka auttavat käyttäjiäsi, on tärkeämpää kuin jokaisen suorituspolun testaaminen.

Tiedän, että saan tästä mielipiteestäni osaltani osaltani kehittäjiä, mutta en välitä. Testien kattavuus on yksi niistä keskusteluista, jotka eivät koskaan lopu.

Kirjoittamasi koodi on yleensä useimmiten oikein. Ei ole tarvetta olla vainoharhainen. Lukuisat testit, jotka rikkoutuvat aina kun muutat jotain, ovat rasite, eivät etu.

Aikasi ja tahdonvoimasi ovat rajalliset. Käytä ne tärkeämpiin tehtäviin.

SwiftUI-sovellusten arkkitehtuuri MVC:n ja MVVM:n avulla

Sovellus on helppo tehdä heittämällä koodia yhteen. Mutta ilman parhaita käytäntöjä ja vankkaa arkkitehtuuria päädyt pian hallitsemattomaan spagettikoodiin. Tässä oppaassa näytän, miten SwiftUI-sovellukset rakennetaan oikein.

SAA ILMAINEN KIRJA NYT

Vastaa

Sähköpostiosoitettasi ei julkaista.