
This video is only available to subscribers. Start a subscription today to get access to this and 484 other videos.
Testing View Controllers - Loading Data
Episode
#339
|
15 minutes
| published on
May 11, 2018
| Uses swift-4.1, Xcode-9.3
Subscribers Only
Testing view controllers can sometimes be challenging. In this episode we will write some tests that verify a view controller loads its data properly from the API client. We will add additional tests to verify that a loading indicator is shown.
This episode is part of a series: Testing iOS Applications.
Testing our View Controller with a Mock API Client
import Foundation
import XCTest
@testable import CoinList
class MockCryptoClient : CryptoCompareClient {
var fetchCallCount: Int = 0
var completeWithResult: ApiResult<CoinList>?
var delay: TimeInterval = 1
var fetchExpectation: XCTestExpectation?
init(completingWith result: ApiResult<CoinList>? = nil) {
super.init(session: URLSession.shared)
completeWithResult = result
}
override func fetchCoinList(completion: @escaping (ApiResult<CoinList>) -> Void) {
fetchCallCount += 1
guard let completeWithResult = self.completeWithResult else { return }
fetchExpectation = XCTestExpectation(description: "coin list retrieved")
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
completion(completeWithResult)
self.fetchExpectation?.fulfill()
}
}
func verifyFetchCalled(file: StaticString = #file, line: UInt = #line) {
XCTAssert(fetchCallCount == 1, "Fetch call count was not called", file: file, line: line)
}
}
Testing the view controller fetches data when first loaded
class CoinListViewControllerTests : XCTestCase {
var viewController: CoinListViewController!
override func setUp() {
super.setUp()
viewController = CoinListViewController.makeFromStoryboard()
}
func testFetchesCoinsWhenLoaded() {
let mockClient = MockCryptoClient()
viewController.cryptoCompareClient = mockClient
_ = viewController.view
mockClient.verifyFetchCalled()
}
private func emptyCoinList() -> CoinList {
return CoinList(response: "",
message: "",
baseImageURL: URL(string: "http://foo.com")!,
baseLinkURL: URL(string: "http://foo.com")!, data: CoinList.Data(coins: []))
}
}
Testing Loading Indicators
func testShowsLoadingIndicatorWhileFetching() {
let mockClient = MockCryptoClient()
viewController.cryptoCompareClient = mockClient
_ = viewController.view
XCTAssert(viewController.activityIndicator.isAnimating)
}
func testLoadingIndicatorHidesWhenFetchCompletes() {
let coinList = emptyCoinList()
let mockClient = MockCryptoClient(completingWith: .success(coinList))
viewController.cryptoCompareClient = mockClient
_ = viewController.view
wait(for: [mockClient.fetchExpectation!], timeout: 3.0)
XCTAssertFalse(viewController.activityIndicator.isAnimating)
}