SwiftUIも結構理解がすすんだので、SwiftUIとTDDを共存する方法をきちんと確認しておこうかと。
テスト対象とするアプリ
今回のアプリは、テキストフィールドがあって、そこに名前を入力してもらって、その人の肩書き(?)を
表示するアプリを対象としましょう。例えば、”Keisuke Honda”と入力すると”Soccer Player”と表示される感じです。
なお、以下の環境で行っています。
- XCode11.4
- Swift5
- iOS向けアプリ
さっそくプロジェクトを作りましょう
TDDの導入
プロジェクトを作る時に、UnitTest、UITestをプロジェクトに追加するかを選択できます。

今回は、”TDDWithTestField”という名前のプロジェクトを作りました。
どのようなファイルがTDD向けに追加されているか確認しましょう。
TDD設定で追加されるファイル

合わせて、TARGETとして、”TDDWithTestFieldTests”と”TDDWithTextFieldUITests”が追加されています。それぞれ、UnitTest、UIUnitTest用のターゲットです。
UnitTestでアルゴリズムのテスト
テストコードの追加
アプリ実装の前にテストコードを実装するのがTDD流なので、エラーが出ることを承知しつつ、テストコードを実装します。
アルゴリズムのテストということで、入力された名前から、その肩書きが返される関数をテストすることとしましょう。
テストする関数は、クラス”FamousPerson”の”title”というStatic関数で名前(:String)を受け取り、肩書き(:String)で返すような以下の関数をテストすることにしましょう。
それに対応するテスト側のコードは、”FamousPersonTest”というUnit Testのファイルを新しく追加して、その中に以下のような関数を追加しましょう。(既存のUnitTest用ファイルに追加してもOKですが、対象クラスごとに分ける方が管理しやすいです)
func testTitle() throws {
XCTAssertEqual(FamousPerson.title(name: "Keisuke Honda"), "Soccer Player")
}
アルゴリズムコードの実装
まずは、コンパイルエラーを解消するために、クラス定義とメソッド定義を行いました。
class FamousPerson {
static func title( name: String) -> String {
return "unknown"
}
}
上記のコードでコンパイルエラーは無くなります。それでは、さっそく、テストしましょう。
現在の実装は、”unknown”と返すだけのコードなので、コンパイルできても、テストを実行するとFailedとレポートされます。

アルゴリズムコードの改良
名前→タイトルの対応付けをMAPに保存しておくことにしましょう。
static func title( name: String) -> String {
let nameTable:[String:String] = ["Keisuke Honda":"Soccer Player"]
return nameTable[name, default: "unknown"]
}
テストも成功するようになりました。

アルゴリズムを改良してくのであれば、”別のテストケースを追加 -> アルゴリズムのコードを改良”を繰り返していくことになります。
ここでは、アルゴリズムはOKとして、UIのテストに進みます。
UIのテスト
以下をテストすることとしました。
- 名前の入力フィールドが見えていること
- place holderのテキストが期待値であること
- “Keisuke Honda”を入力すると、ラベルが、”Soccer Player”になること
- ”HenoHeno Moheji”を入力すると、ラベルが、”unknown”になること
UIテストの実装
ということで、以下を実装
func testKeisukeHonda() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// check textfield availability
let textField = app.textFields["NameTextField"]
XCTAssertTrue(textField.isEnabled)
XCTAssertEqual(textField.placeholderValue, "enter name")
// check behavior
textField.tap()
textField.typeText("Keisuke Honda")
let titleLabel = app.staticTexts["TitleLabel"]
XCTAssertEqual(titleLabel.label, "You are Soccer Player")
}
(UI実装していないので、当たり前ですが)、失敗します。

UIの実装
では、UIの実装をしていきましょう。
@State var userName:String = ""
var body: some View {
VStack {
Spacer()
TextField("enter name", text: $userName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.accessibility(identifier: "NameTextField")
Spacer()
Text("You are \(FamousPerson.title(name: userName) )")
.accessibility(identifier: "TitleLabel")
Spacer()
}
}


UITestの確認
改めて、UIテストを実行するとOKになることが確認できます。

まとめ
SwiftUIでもUIKitでもおおよそ同じようにTDDすることができます。
Storyboard等で設定していたaccessibilityは、”.accessibility(identifier:”FooBar”)という形で設定することとなります。
それさえわかれば、あとは、UIKit,SwiftUI同じです。
UIの改良、さらに超高効率で改良するためのTips
テキストフィールドが左右一杯に広がっているのって、違和感ありますよね。
TextFieldのmodifierで、左右に若干のスペースを設定できるものがあったと思うのですが・・・と思って、探し回りました。
“.padding()”でした!
改良したUIは、こちら。

SwiftUIには、このように”大抵の人が欲しいと思う調整”がすでに揃っている気がします。
自分で探すのも1つですが、”SwiftUI Views Mastery Bundle”という本が超便利です。
Sponsor Link




