Swift,Objective-Cプログラミング ~ iOS ~

Objective-C,Swift,Apple Watchなどのプログラミング

【iOS Swift入門 #302】非同期処理のobservableをテストする(RxSwift, RxBlocking)

はじめに

非同期処理のobservableをテストをする場合、RxBlockingを使います。 RxBlockingはRxSwiftレポジトリに含まれていますが、RxSwiftとは別にimportする必要があります。

RxBlogkingに含まれているtoBlockingメソッドを使うと、非同期のobservableを同期のobservableに変換することができます。toBlockingメソッドを使わなくても非同期処理のテストを書くことができますが、書かなければいけないコードが多くなります。

テストコード

iTunes Search APIを使った検索処理」をテストします。 affiliate.itunes.apple.com

テスト対象

SearchAPI構造体を作成しました。

import Foundation
import RxSwift
import RxCocoa

struct SearchAPI{
    typealias JSONType = [String:Any]
    private static let baseURL = "https://itunes.apple.com/search?term="
    
    static func search(term:String) -> Observable<JSONType>{
        let urlString = baseURL + term
        let url = URL(string: urlString)!
        let request = URLRequest(url: url)
        
        return URLSession.shared.rx.response(request: request)
            .filter{ return (200 ..< 300 ~= $0.0.statusCode) }
            .map{ (_, data) -> JSONType in
                guard
                    let json = try? JSONSerialization.jsonObject(with: data, options: []),
                    let result = json  as? JSONType
                else{
                    return [:]
                }
                return result
            }
    }
}

search(term:)は与えられた検索文字列でiTunes Search APIに検索リクエストを実行します。内部ではURLSessionが使われています。URLSessionのリクエストは非同期で実行されるため、search(term:)は非同期処理となります。search(term:)メソッドをXCTestでテストします。

コード

APIJSONレスポンスにresultCountというキーがあります。有名なアーティストの名前を検索条件にすれば、たいてい1以上の値が返ってきます。この値が1以上であることをテストします。

RxBlockingを使った場合テストコード、使わない場合のテストコードを書きました。

import XCTest
@testable import SampleRx

import RxSwift
import RxTest
import RxBlocking

class SampleRxTests: XCTestCase {
    private let disposeBag = DisposeBag()
    
    // RxBlockingを使わなかった場合
    func testSearchAPI_normal(){
        let observable = SearchAPI.search(term: "johnson")
        
        var result = [String: Any]()
        let expectation = self.expectation(description: #function)
        observable.subscribe(onNext: { json in
            result = json
            expectation.fulfill()
        })
        .disposed(by: disposeBag)
        
        
        waitForExpectations(timeout: 1.0){ error in
            let resultCount = result["resultCount"] as! Int
            XCTAssertTrue(resultCount > 0)
        }
    }
    
    // RxBlockingを使った場合
    func testSearchAPI(){
        let observable = SearchAPI.search(term: "johnson")
        let result = try! observable.toBlocking().last()!
        let resultCount = result["resultCount"] as! Int
        
        XCTAssertTrue(resultCount > 0)
    }
}

RxBlockingを使ったほうがテストコードの行数が少なくなります。そのため、わかりやすいと思いませんか?

サンプル

こちらからダウンロード SampleRx.zip - Google ドライブ

Swift

入門書籍

絶対に挫折しない iPhoneアプリ開発「超」入門 増補改訂第5版
プログラミングが初めて!という人が小さなアプリを作ることで、アプリ開発を学ぶことができます。
「Swiftだけでなく、プログラミング自体が初めてなんだけど、どの本が良い?」と聞かれたときには、
この書籍をおすすめしています。

本気ではじめるiPhoneアプリ作り Xcode 8.x+Swift 3.x対応 (ヤフー黒帯シリーズ)
アプリ開発からApp Storeへの公開までの一通りを学ぶことができます。
入門書を2冊、3冊を読んだあとでこの書籍を読むとかなりの実力アップを感じることができます。

ただし、一通り学ぶことができますが、プログラミング初めてでこの書籍を選ぶことはオススメできません。
最初の方の内容はプログラミング初心者には理解が難しく、そこで勉強をやめてしまう可能性がありそうだと感じます。

Swiftポケットリファレンス
辞書として1冊は持ってても良い。

仕事でやれるレベルになるために

初心者から仕事でやれるレベルになるためにオススメできる日本語書籍がみつかりませんでした。
英語は苦手でも、書籍に書かれているソースはやさしく、読み進めることができます。

The iOS Apprentice (英語サイト・英語書籍)
Swift Apprentice (英語サイト・英語書籍)

平均的プログラマーを超えるために

詳解Swift 第3版
Swift3の書籍。第1版、第2版にもお世話になっています。
Swiftの文法についてとても詳しく書いてあります。

Ray Wenderlich | Tutorials for iPhone / iOS Developers and Gamers
QiitaのSwiftに関する記事