LoginSignup
9
7

More than 1 year has passed since last update.

Swift Playgrounds のアプリでテストを書く

Last updated at Posted at 2022-09-03

初めに

まず最初に Xcode の Playground とは違います のでmm
今回は Swift Playgrounds でアプリを開発する場合のお話です。

Swift Playgrounds とは

2016年に登場した iPad 上で Swift を学習できるアプリです。

当初はテンプレートの教材を Swift で学習するだけでした。

現在はバージョンが4.1までリリースされており、iPad のみならず Mac 上でも動作し、実際にリリースできるアプリが作成できるまでになりました。

どんなことができるの?

iOSDC Japan 2022 で LT をしました!
資料をあげたので、見ていただけると少しは理解が深まるかと思いますmm

テストコードの実装方法

今回は一部の作業を iPad ではなく Mac で行う必要があります。
iPad でもファイル操作可能なアプリを入れればできるかと思いますが、未確認です。

1. 前提

Swift Playgrounds では、テストを書く機構がありません。
また、Xcode でアプリを開いたとしても、追加することはできません。

そこでライブラリを使っていきます。

Swift Playgrounds で作成するアプリで、テストをかけるようにするライブラリです。

ただし、Swift Playgrounds は、そもそも複数のターゲットを持てません。
つまり、ライブラリを追加しても、プロダクションコードの中にテストを書くことになります。

ライブラリのコードは、ビルドして配布する過程で除かれるので、容量にはほとんど影響がありません。

補足

ライブラリのテスト実行方法ですが、以下の記事にも言及されている方法なのではないかと思います
(ざっとライブラリコードを見た感じですが)

内部的には Objective-C のランタイムを使って、テストの実行を行なっていそうです。

2.導入

① Swift Package Manager での導入

Swift Playgrounds のデフォルトで唯一サポートされている Swift Package Manager で追加します。

② コンパイル時の設定を追加

① だけでも動作しますが、フラグを追加しないとアプリ配布時にテストコードが含まれてしまいます。それを防ぐための設定をします。

アプリの「パッケージの内容を表示」で、中身を見ることができます。

そこにある、 Packaget.swift に設定を追加します。

.swift
/* 略 */

targets: [
    .executableTarget(
        name: "AppModule",
        dependencies: [
            .product(name: "PlaygroundTester", package: "playgroundtester")
        ],
        path: ".",
        swiftSettings: [
            .define("TESTING_ENABLED", .when(configuration: .debug)) // これ
        ]
    )
]

/* 略 */

これで導入は完了です。

3. 実装

Xcode のテストとは違い、プロダクションコードで実行する必要があります。
その結果を View で表示して確認できるようにしたのが、このライブラリの特徴です。

.swift
struct Myapp: App {
    init() {
        PlaygroundTester.PlaygroundTesterConfiguration.isTesting = true
    }
    var body: some Scene {
        WindowGroup {
            PlaygroundTester.PlaygroundTesterWrapperView {
                // YourContentView()
            }
        }
    }
}

フラグを false にすれば自身が作成した View を閲覧できます。仮に true のまま間違ってストアに上げても、内部的にはアプリの View を返すようになっているのでそこは安心です。

実際の例を交えて見ていきます。
ここでは、以下のモデルをテストする場合を想定していきます。

.swift
class Model {
    var counter = 0
    
    func add() {
        counter += 1
    }
    
    func remove() {
        counter -= 1
    }
}

テストコードはこのようになります。

.swift
import PlaygroundTester // <- テストできるようにする

@objcMembers // <- これがないとテストが動かない
final class ModelTest: TestCase {
    
    func testAdd() {
        let model = Model()
        AssertEqual(model.counter, other: 0)
        
        model.add()
        AssertEqual(model.counter, other: 1)
    } 
    
    func testRemove() {
        let model = Model()
        AssertEqual(model.counter, other: 0)
        
        model.remove()
        AssertEqual(model.counter, other: -1)
    } 
}
  • PlaygroundTesterimport をする
  • テストクラスに @objcMembers をつける

を忘れないようにしましょう。

また、その際の View ではこのように結果を確認できます。
view

Xcode のテストと同様に testXXX となっている関数のみがテストとして実行されます。
また、Assert 系も一通りあるので、Xcode のテストと同じような書き方を実現できます。

.swift
public func Assert(_ value: Bool, message: String = "")
public func AssertFalse(_ value: Bool, message: String = "")
public func AssertEqual<T: Equatable>(_ value: T, other: T, message: String = "") 
public func AssertNotEqual<T: Equatable>(_ value: T, other: T, message: String = "")
public func AssertNil<T>(_ value: T?, message: String = "")
public func AssertNotNil<T>(_ value: T?, message: String = "")
public func AssertUnwrap<T>(_ value: T?, message: String = "") throws -> T
public func AssertExpectations(_ expectations: [Expectation], timeout: TimeInterval)

全てあるわけではないので、アップデートを待ちましょう。
(またはPRを投げましょう!)

ちなみにライブラリの実装的に
AssertEqual(期待値, other: 受け取った値)
のようですが、違和感があるので自分は逆に実装しています。

4. 出来ないこと

個人で開発されているライブラリのため、機能がまだまだ浅い面もあります。

リポジトリにも書かれていますが

  • Combine のサポート
  • async/await のサポート

このあたりは後回しのようです。

少し冗長ではありますが、Expectation はあるので、Comebine はしばらくはそれで書くしかなさそうです。

ロードマップがあり、Github の issue としては積まれているので、気長に待つかPRを投げましょう。

終わりに

今回は自前でテストコードを書く方法を紹介しました。

Swift Playgrounds はアップデートされるたびに出来ることがかなり増えています。
なので、近い将来サポートされることを願いつつ...といったところでしょう。

リポジトリ

以下に導入したアプリがあるので、参考程度に見ていただけますと🙏

その他

関連記事はこちら

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7