Jak testovat soukromé metody ve Swiftu

Stáhněte si zdarma kopii knihy
Chybějící příručka
pro vývoj ve Swiftu

Příručka, kterou bych si přál mít, když jsem začínal

Přidejte se k 20,000+ Vývojáři, kteří se učí o vývoji ve Swiftu

Stáhněte si bezplatnou kopii

Testování projektu ve Swiftu je zcela odlišné od unit testování projektu napsaného v Objective-C. Ti, kteří jsou zvyklí na flexibilitu běhového prostředí Objective-C, mohou mít pocit, že mají svázané ruce za zády.

Řízení přístupu

Řízení přístupu je sice velmi vítaný doplněk s mnoha výhodami, ale může komplikovat testování jednotek, zejména pokud s testováním jednotek začínáte. Pravděpodobně víte, že můžete použít atribut testable na příkaz import v cíli testu, abyste získali přístup k entitám, které jsou deklarovány jako interní.

import XCTest@testable import Notesclass NotesTests: XCTestCase { ...}

Ačkoli je to vhodný doplněk, neumožňuje vám přístup k soukromým entitám v cíli testu. Tím se dostáváme k otázce dne. Jak testujete privátní entity?

Špatná otázka

Krátká odpověď na tuto otázku je jednoduchá. K privátním entitám nelze přistupovat z jiného modulu, což platí i pro testovací cíle. Prostě a jednoduše. K tomu slouží řízení přístupu.

Ale to není odpověď na tuto otázku. Pokud se ptáte, jak testovat soukromé entity, pak se ptáte špatně. Ale proč tomu tak je?

Nic vám do toho není

Proč deklarujete entitu jako soukromou? Jakou k tomu máte motivaci? Podívejte se na následující příklad:

import Foundationstruct AccountViewViewModel { // MARK: - Properties let account: Account // MARK: - Public Interface var subscriptionAsString: String { switch account.subscription { case .monthly: return "Monthly Subscription" case .yearly: return "Yearly Subscription" case .trial: return "Trial Subscription" } } var expiresAtAsString: String { // Parse Date let date = parse(date: account.expiresAt) // Initialize Date Formatter let dateFormatter = DateFormatter() // Configure Date Formatter dateFormatter.dateFormat = "YYYY, MMMM" // Convert Date to String return dateFormatter.string(from: date) } // MARK: - Private Interface private func parse(date dateAsString: String) -> Date { let dateFormat: String if dateAsString.contains("/") { dateFormat = "YYYY'/'MM'/'dd" } else { dateFormat = "YYYYMMdd" } // Initialize Date Formatter let dateFormatter = DateFormatter() // Configure Date Formatter dateFormatter.dateFormat = dateFormat if let date = dateFormatter.date(from: dateAsString) { print(date) return date } else { fatalError("Incompatible Date Format") } }}

Rád bych otestoval strukturu AccountViewViewModel. Jak vidíte, struktura AccountViewViewModel vystavuje dvě vnitřní vypočtené vlastnosti a také definuje soukromou metodu. Výpočtová vlastnost expiresAtAsString přenáší část své práce na soukromou metodu parse(date:). Testování vnitřních vypočtených vlastností je jednoduché.

// MARK: - Tests for Subscription as Stringfunc testSubscriptionAsString_Monthly() { let account = Account(expiresAt: "20161225", subscription: .monthly) let accountViewViewModel = AccountViewViewModel(account: account) XCTAssertEqual(accountViewViewModel.subscriptionAsString, "Monthly Subscription")}func testSubscriptionAsString_Yearly() { let account = Account(expiresAt: "20161225", subscription: .yearly) let accountViewViewModel = AccountViewViewModel(account: account) XCTAssertEqual(accountViewViewModel.subscriptionAsString, "Yearly Subscription")}func testSubscriptionAsString_Trial() { let account = Account(expiresAt: "20161225", subscription: .trial) let accountViewViewModel = AccountViewViewModel(account: account) XCTAssertEqual(accountViewViewModel.subscriptionAsString, "Trial Subscription")}// MARK: - Tests for Expires at as Stringfunc testExpiresAtAsString_20161225() { let account = Account(expiresAt: "20161225", subscription: .trial) let accountViewViewModel = AccountViewViewModel(account: account) XCTAssertEqual(accountViewViewModel.expiresAtAsString, "2016, December")}

Jak ale otestujeme soukromou metodu? K soukromé metodě nemůžeme z cíle testu přistupovat. Proč bychom ale měli unit testovat soukromou metodu? Označili jsme ji jako soukromou z nějakého důvodu. Je to tak? A tím se dostáváme k odpovědi na otázku, kterou jsme začali. Soukromé metody netestujeme.

Unit testování veřejného rozhraní

Testováním veřejného rozhraní struktury AccountViewViewModel automaticky nebo implicitně unit testujeme soukromé rozhraní struktury. Vaším úkolem je zajistit, aby veřejné rozhraní bylo důkladně otestováno. To znamená, že musíte zajistit, aby každá cesta kódu struktury AccountViewViewModel byla pokryta unit testy. Jinými slovy, sada unit testů by měla vést k úplnému pokrytí kódu. To zahrnuje veřejné, interní a soukromé entity.

Pokud v Xcode povolíme pokrytí kódu a spustíme unit testy struktury AccountViewViewModel, uvidíme, že některé cesty kódu nejsou provedeny.

Pokrytí kódu v Xcode

To nám říká, že unit testy nejsou úplné. Cestu kódu můžeme ignorovat pro fatální chybu. Nikdy netestuji cesty kódu, které vedou k fatální chybě, ale to do značné míry závisí na tom, jak používáte fatální chyby ve svých projektech.

Pokrytí kódu pro strukturu AccountViewViewModel můžeme zvýšit přidáním ještě jednoho unit testu.

func testExpiresAtAsString_20161225WithForwardSlashes() { let account = Account(expiresAt: "2016/12/25", subscription: .trial) let accountViewViewModel = AccountViewViewModel(account: account) XCTAssertEqual(accountViewViewModel.expiresAtAsString, "2016, December")}

Krytí kódu v Xcode

Implementace a specifikace

Důležité je pochopit, že testujeme specifikaci struktury AccountViewViewModel. Netestujeme její implementaci. I když to může znít podobně, ve skutečnosti je to velmi odlišné. Testujeme funkčnost struktury AccountViewViewModel. Nezajímá nás, jak provádí svá kouzla pod kapotou.

Klíčovým poznatkem z tohoto článku je, že privátní entity není třeba unit testovat. Testování jednotek je formou testování černé skříňky. To znamená, že netestujeme implementaci struktury AccountViewViewModel, ale její specifikaci.

To však neznamená, že nás implementace nezajímá. Musíme se ujistit, že sada jednotkových testů pokrývá všechny cesty kódu testované entity. K dosažení tohoto cíle jsou neocenitelné zprávy o pokrytí kódu.

Stáhněte si zdarma kopii knihy
Chybějící příručka
pro vývoj ve Swiftu

Příručka, kterou bych si přál mít, když jsem začínal

Připojte se k více než 20 000 vývojářům, kteří se učí o vývoji ve Swiftu

Stáhněte si zdarma kopii knihy

.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.