しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Xcodeで単体テストとUIテストを試してみる

Xcode上でユニットテストとUIテストを作って動かしてみました。
ユニットテストは過去に下記事で試したんですが時間が経ったので再度試してみました。

llcc.hatenablog.com

ユニットテストを動かす

まずはプロジェクトを作成します。
作成時、Include TestsをONにします。

f:id:llcc:20220306114313p:plain

プロジェクトを作成すると下のようにテストファイルが作られます。

f:id:llcc:20220306114808p:plain

テスト用のターゲットも作られました。

f:id:llcc:20220306114829p:plain

テストはテストファイル左側のひし形ボタンをタップする事で実行できます。

f:id:llcc:20220306115612p:plain

左メニューのTest Navigatorから実行する事もできます。

f:id:llcc:20220306115714p:plain

実行すると結果が表示されます。

f:id:llcc:20220306115938p:plain

ユニットテストを追加する

次は実際にテストを書いていきます。
テストは下のようにXCTAssertから始まるメソッドを使って書いていきます。

class MyAppTests: XCTestCase {
    func testExample() throws {
        XCTAssertEqual(1, 1, "Test1")
        let value: Int? = nil
        XCTAssertNil(value, "Test2")
    }
}

テストの追加は下の通りです。
testから始まるメソッドを追加すれば自動的にテストとして認識されます。

class MyAppTests: XCTestCase {
    func testExample() throws {
        XCTAssertEqual(1, 1, "Test1")
        let value: Int? = nil
        XCTAssertNil(value, "Test2")
    }
    
    func testExample2() throws {
        XCTAssertEqual(1, 1, "Test3")
    }
}

measureというメソッドでメソッドの実行速度の記録も可能です。

class MyAppTests: XCTestCase {
    func testPerformanceExample() throws {
        self.measure {
            _ = (0...100000).reduce(0, { $0 + $1 })
        }
    }
}

実行後は下のような表示になります。

f:id:llcc:20220306133300p:plain

DBの作成など、テスト前の準備や片付けがある場合は下メソッドに記入していきます。

class MyAppTests: XCTestCase {
    override func setUpWithError() throws {
    }

    override func tearDownWithError() throws {
    }
}

UIテストを動かす

続けてUIテストも試していきます。
Main.storyboardにラベルとボタンを配置します。

f:id:llcc:20220306140546p:plain

ViewController.swift側にタップしたらラベルの文字を変える処理を追加してからStoryboardとの紐付けを行います。

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    
    @IBAction func tapButton() {
        label.text = "Tapped"
    }
}

続けてテストを記述します。
まずはラベルが存在する事を確認します。
確認コードは下の通りです。

class MyAppUITests: XCTestCase {
    func testExample() throws {
        let app = XCUIApplication()
        app.launch()
        
        XCTAssertTrue(app.staticTexts["MyLabel"].exists)
    }
}

AccessibilityのIdentifierを設定しておけばそのIDでラベルを取得する事もできます。

XCTAssertEqual("MyLabel", app.staticTexts["ViewConrollerLabel"].label)

f:id:llcc:20220306163542p:plain

テスト実行すると無事に成功マークが出ました。

f:id:llcc:20220306141254p:plain

次はボタンタップのテストを追加します。
処理は下の通りです。

tapメソッドでタップ処理を行い、その後ラベルの値が変わったかどうかをテストしています。

class MyAppUITests: XCTestCase {
    func testExample() throws {
        let app = XCUIApplication()
        app.launch()
        
        XCTAssertTrue(app.staticTexts["MyLabel"].exists)
        app.buttons["MyButton"].tap()
        XCTAssertFalse(app.staticTexts["MyLabel"].exists)
        XCTAssertTrue(app.staticTexts["Tapped"].exists)
    }
}

下のようなコードで画面のスクリーンショットを取る事も可能です。

class MyAppUITests: XCTestCase {
    func testExample() throws {
        let app = XCUIApplication()
        app.launch()
        
        let attachment1 = XCTAttachment(screenshot: app.screenshot())
        attachment1.name = "Launched"
        attachment1.lifetime = .keepAlways
        add(attachment1)
        
        XCTAssertTrue(app.staticTexts["MyLabel"].exists)
        app.buttons["MyButton"].tap()
        XCTAssertFalse(app.staticTexts["MyLabel"].exists)
        XCTAssertTrue(app.staticTexts["Tapped"].exists)
        
        let attachment2 = XCTAttachment(screenshot: app.screenshot())
        attachment2.name = "Tapped"
        attachment2.lifetime = .keepAlways
        add(attachment2)
    }
}

スクリーンショットは左メニューのReport navigatorから見る事ができます。

f:id:llcc:20220306161911p:plain