Help us understand the problem. What is going on with this article?

[iOS、Swift] ユニットテストの時に、任意のタイミングでViewDidLoad()、ViewWill(Did)Appear()、ViewWill(Did)Disappear()を呼び出す方法

More than 3 years have passed since last update.

忘れがちなので備忘も兼ねてまとめておきます。

事前準備

以下のようなView Controller(Initial View Controller)を作成します。

HogeViewController.swift
import UIKit

class HogeViewController: UIViewController {

    // ViewDidLoad()用フラグ
    var isViewDidLoadCalled = false

    // ViewWill(Did)Appear()用フラグ
    var isViewWillAppearCalled = false
    var isViewDidAppearCalled = false

    // ViewWill(Did)Disappear()用フラグ
    var isViewWillDisappearCalled = false
    var isViewDidDisappearCalled = false

    // MARK: - View Controller Lifecycle Methods
    override func viewDidLoad() {
        super.viewDidLoad()
        self.isViewDidLoadCalled = true
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.isViewWillAppearCalled = true
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.isViewDidAppearCalled = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.isViewWillDisappearCalled = true
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        self.isViewDidDisappearCalled = true
    }
}

次に、このView Controllerをテストするファイルを作成し、以下のようなセットアップを行います。

HogeViewControllerTests.swift
import XCTest
@testable import InvokeVCLifecycleMethods

class HogeViewControllerTests: XCTestCase {

    var hogeVC: HogeViewController!

    override func setUp() {
        super.setUp()

        let storyboard = UIStoryboard(name: "Main", bundle: nil)

        hogeVC = storyboard.instantiateInitialViewController() as! HogeViewController
    }

    override func tearDown() {
        super.tearDown()
    }

    func test_ViewDidLoad_Called() {
        XCTAssertTrue(hogeVC.isViewDidLoadCalled)
    }

    func test_ViewWillAndDidAppear_Called() {
        XCTAssertTrue(hogeVC.isViewWillAppearCalled)
        XCTAssertTrue(hogeVC.isViewDidAppearCalled)
    }

    func test_ViewWillAndDidDisappear_Called() {
        XCTAssertTrue(hogeVC.isViewWillDisappearCalled)
        XCTAssertTrue(hogeVC.isViewDidDisappearCalled)
    }

}

この状態でテストを実行すると、全てのテストがFailします。

all_failed.png

これで事前準備は完了です。

View Controller LifeCycleメソッドを呼び出す

それでは早速、各種メソッドを呼び出していきましょう。

ViewDidLoad()

ViewDidLoad()は、View Controllerのviewプロパティにアクセスすることで呼び出せます。

[追記] @kazuhiro4949さんより、viewへのアクセスではなくloadViewIfNeeded()ViewDidLoad()を呼び出す方法を教えていただきました。ありがとうございます!

    func test_ViewDidLoad_Called() {
        // ViewDidLoad()を呼び出す
        hogeVC.loadViewIfNeeded()

        XCTAssertTrue(hogeVC.isViewDidLoadCalled)
    }

結果

pass1.png

Passしました。

ViewWill(Did)Appear()

ViewWillAppear()は、UIViewControllerにbeginAppearanceTransition(_:animated:)というインスタンスメソッドが用意されており、その第一引数(_ isAppearing: Bool)をtrueにして呼ぶことで呼び出せます。ViewDidAppear()は、そのインスタンスメソッドを呼んだ後にendAppearanceTransition()を呼ぶことで呼び出せます。

        // ViewWillAppear()を呼び出す(第一引数をtrueにする)
        hogeVC.beginAppearanceTransition(true, animated: false)
        // ViewDidAppear()を呼び出す
        hogeVC.endAppearanceTransition()

結果

pass_appear.png

これもPassしました。

ViewWill(Did)Disappear()

ViewWillDisappear()は、先程のbeginAppearanceTransition(_:animated:)の第一引数(_ isAppearing: Bool)をfalseにして呼ぶことで呼び出せます。ViewDidDisappear()は、その後にendAppearanceTransition()を呼ぶことで呼び出せます。

    func test_ViewWillAndDidDisappear_Called() {
        // ViewWillDisappear()を呼び出す(第一引数をfalseにする)
        hogeVC.beginAppearanceTransition(false, animated: false)
        // ViewDidDisappear()を呼び出す
        hogeVC.endAppearanceTransition()

        XCTAssertTrue(hogeVC.isViewWillDisappearCalled)
        XCTAssertTrue(hogeVC.isViewDidDisappearCalled)
    }

結果

pass_disappear.png

全てPassしました。

ユニットテストを書く時にご活用ください。

参考

Work with View Controllers
https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/WorkWithViewControllers.html)

[追記] loadViewIfNeeded()
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621446-loadviewifneeded

beginAppearanceTransition(_:animated:)
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621387-beginappearancetransition

endAppearanceTransition()
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621503-endappearancetransition

iOS: The One Weird Trick For Testing View Controllers in Swift

Testing in Swift

mii-chan
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away