🐱

【iOS/Swift】環境変数を使ったFactory MethodパターンでMockClientに切り替える方法

2023/11/03に公開

はじめに

今回は、iOSアプリを開発している私がUnitTestを学習している中で遭遇したFactory Methodパターンという設計パターンについて、実例とともにまとめています。

Factory Methodパターンとは?

Factory Methodパターンは、オブジェクトの生成をサブクラスに委任することで、具体的なクラスの選択をクライアントから分離し、柔軟性を提供する設計パターンです。

実際にSwiftではどのように書くことができるのか

今回は、API通信をするアプリにおいて、テスト時にはMockWebServiceが呼ばれるように実装する例を紹介します。

前提

  • Xcode Version 15.0.1 (15A507)
  • macOS Sonoma 14.1(23B74)

以下がFacotoryMethodパターンの一例です。

import Foundation

class NetworkServiceFactory {

    static func create() -> NetworkService {

        let environment = ProcessInfo.processInfo.environment["ENV"]

        if let environment = environment {
            if environment == "TEST" {
                return MockWebservice()
            } else {
                return Webservice()
            }
        } else {
            return Webservice()
        }
    }
}

このコードでは、NetworkServiceFactoryクラスにcreateメソッドがあり、このメソッドはNetworkService型のオブジェクトを生成して返します。ただし、生成する具体的なクラスは、環境変数 "ENV" の値に依存しています。具体的には、"ENV" の値が "TEST" の場合はMockWebserviceを返し、それ以外の場合はWebserviceを返します。ただし、UnitTestでmockClientを呼び出すためには、環境変数を"TEST"と次のように明示する必要があります。

import XCTest

final class UnitTest: XCTestCase {
    private var app: XCUIApplication!
    
    override func setUp() {
        app = XCUIApplication()
        continueAfterFailure = false
        app.launchEnvironment = ["ENV": "TEST"]  // 環境変数に”TEST”を定義。
        app.launch()
    }
    ...
}

この設計により、クライアントコードは具体的なNetworkService実装クラスを直接インスタンス化せずに、Factoryを介して生成できます。クライアントコードはNetworkServiceFactory.create()を呼び出すだけで、適切な実装クラスが選択されます。これにより、アプリケーションの状態や設定に応じて異なる実装を使用できる柔軟性が提供されます。この柔軟性はFactory Methodパターンの主要な特徴です。

今回は、環境変数での分岐処理をFactoryクラスに持たせる形の実装を紹介しましたが、他の使い方としては読み込むデータ形式に応じて処理を変えるなどするときに同様にcreate()メソッドを呼び出すだけで適切なクラスを選択するという方法もあります。

おわりに

デザインパターンについて、勉強を始めたばかりなので、間違っている部分などがあれば気軽にコメントを頂けると嬉しいです!

参考資料

https://qiita.com/shoheiyokoyama/items/d752834a6a2e208b90ca
https://developer.apple.com/documentation/foundation/processinfo/1417911-environment

Discussion