it-swarm-ja.com

Swift

私はSwiftでテスト可能なクラスを設計する方法について長い間探していましたが、すべての情報サイトはテストする方法、主張する方法、なぜテストが良いのか)のような基本的なことを説明しています...

私の現在の設計(これが最善かどうかはわかりませんが)には、ApiClientで初期化されるシングルトンAppDelegateクラスが含まれています。このようなもの:

// Inside AppDelegate#application:didFinishLaunchingWithOptions
ApiClientFactory.make();

// Inside ApiClientFactory
static func make() {
    ApiClient.initialize(
        userProvider: UserProvider(UserLocalRepo(), UserRemoteRepo()),
        booksProvider: BooksProvider(BookLocalRepo(), BookRemoteRepo()),
        ...
    )
}

アイデアは、テスト時に*Providersクラス、モックリポジトリに注入することでした。しかし、VCsがインスタンス化される方法のため、これが適切な設計であるかどうかはまったくわかりません。また、AppDelegate#application:didFinishLaunchingWithOptionsがまだ実行されているように見えるため、これらのモックリポジトリをどこに挿入するかわかりません。テスト時(つまり、ApiClientは、模擬クラスではなく、実際のクラスで初期化されます)

テスト中に共通の問題点に直面していると思います。シングルトンの実装が嫌いな理由の1つです。これらのリポジトリインスタンスを挿入することは、実装を変更することなく、将来的にテストダブルを置き換えたり、APIクライアントの構成を変更したりできる便利なパターンです。ただし、シングルトンとして実装すると、お気づきのように、この柔軟性の多くが失われます。呼び出されているapplication:didFinishLaunchingWithOptions:メソッドに対処する必要があるだけでなく、このシングルトンの共有状態が1つのテストから後続のテストにリークしないように注意する必要があります。

1つのオプションは、初期化後にこれらのリポジトリを変更できるようにすることです。これにより、後でそれらをテストダブルに置き換えることができます。残念ながら、これにより、アプリで許可したくない変更可能な構成も可能になります。

私の好みは、シングルトンをまったく使用せず、このApiClientクラスを、それを使用する必要のあるコンポーネントに注入されたクラスのインスタンスに置き換えることです。その後、必要に応じて、各テストに分離された独立したインスタンスを作成できます。アプリケーションでは、おそらく1つのApiClientインスタンスしかありませんが、クラスメソッドを介してアクセスしたり、実装の制約として適用したりする必要があるわけではありません。

4
Jonah

シングルトンはApple APIでは悪い考えです。Objective-Cはシングルトンをサポートしていません。代わりに、他のインスタンスの形成をブロックする1つのインスタンスを作成します。これは、IMHOを回避する大まかな作業です。 tは常に機能します。Swiftでこれ以上良いとは思いません。また、Objc APIをサポートする必要があることを考えると、私はそれを疑っています。

単一のインスタンスを確保するための推奨される方法は、オブジェクトをアプリデリゲートのプロパティとして配置することです。アプリは1つだけで、デリゲートも1つしかなく、アプリデリゲートは常に有効であるため、面倒なことなくシングルトンのすべての利便性を利用できます。アプリデリゲートは常にアクセス可能であるため、「シングルトン」はアプリ内のどこからでもアクセスできます。

その後、ユニットテストは正常に進行します。

2
TechZen