#はじめに
先日、Yahoo! JapanのiOS黒帯インターンに参加させていただいたので、そこで利用されていた『TDD(テスト駆動開発〕』という開発手法を簡単にまとめてみました。
また、今回はSwift3
で実装しています。Xcode
を事前にインストールしておきましょう。
ちなみに、インターン自体の感想などはブログの方にアップしているので、興味のある方はぜひご覧ください。
Yahoo!iOS黒帯インターンでの思い出
#テスト駆動開発(TDD)
##テスト駆動開発とは
テスト駆動開発は,小さなステップを繰り返してプログラムの設計と開発を行っていくソフトウェア開発手法です。テスト駆動開発は次の3ステップから構成されています。
- テストを書く
- 最低限の実装をする
- リファクタリング
(参考文献: 和田卓人のテスト駆動開発講座)
もう少し詳しくみてみましょう。
##テスト駆動開発の進め方
テスト駆動開発では、下の画像のように3つのステップに沿って開発を進めていきます。
###1. テストを書く
テスト駆動開発では、まずはじめに追加したい機能のテストを書きます。ここでの「テスト」とは、開発者がコードで書くテスト用プログラムのことです。テストを書くことで、実装したものが正常に動いているかを自動で確認できます。
このときに大事なことは、「テストを一つだけ書く」ことです。
テスト駆動開発では機能の一つ一つを小さく作り洗練させていくことで、開発スピードと実装の正当性を実現しています。なのでTDDで開発をする際は、できるだけ「小さく」開発することが必要です。
出来上がったテストを実行してみると必ず「失敗」します。これは当たり前で、実現したい機能の最終形をテストで書いても実装はまだしていないからです。
テスト駆動開発ではこの状態を「Red(失敗)」といいます。
###2. 最低限の実装をする
テストが書けたら次は実装を行います。ここで大事なことは「最低限の実装をする」ことです。
コードの再利用性や設計の美醜を考えるのではなく、テストが通るもっともシンプルな実装をします。
これによって、余計なことを考え作業を中断したことで開発スピードが落ちることはなくなります。
実装が正しく行われていれば、この時点でテストが通ります。
テスト駆動開発ではこの状態を「Green(成功)」といいます。
###3. リファクタリング
実装をしたことでテストが通るようになり、機能が実現できました。しかし、最低限の実装をしたことでコードに無駄があったり愚直過ぎるコードだったりと,いくつか直したい点があると思います。
テスト駆動開発では、テストが通るままの状態でコード内部の設計をよくしていきます。このような作業のことを「リファクタリング」といいます。
リファクタリングすることで、ソースコードの重複や実装の最適化が行われ、メンテナンスなどがしやすくなります。
テスト駆動開発の流れが分かってきたと思うので、次は具体的にiOSでのテスト駆動開発がどのように行われるかみてみましょう。
#iOSでのテスト手法
##XCTest
XCTestとは、Xcode5
から導入されたテストフレームワークです。iOS上でUnitTestを行う際にはよく使われますね。他にも外部テストフレムワークが存在しますが、今回はこちらのフレームワークを使ってみます。
##Quick
Quickは、Swift
とObjective-C
のための**ビヘイビア駆動開発フレームワーク(BDD Framework)**です。
簡単にいうと、Xcode上でテストを書くための外部フレームワークです。
ビヘイビア駆動開発フレームワークについての説明はここでは省略させていただきます。
今回は使用しませんが、有名なので覚えておくといいでしょう。
#実装
##作りたいもの
今回は、スクリーン上に「Hello, Qiita.」が表示されるようにしましょう。
##1. テストを書く
現在は上記画像のように「Hello, World.」が表示されていることにします。
では、テストを書いてみましょう。
「TestSample」というプロジェクトで行いたいと思います。まずは、左側のNavigation Area
から**TestSampleTests.swift
**を開きます。
import XCTest
@testable import TestSample
class TestSampleTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testLabelTitle() {
let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
let viewController = storyBoard.instantiateViewController(withIdentifier: "viewController") as? ViewController
viewController?.viewDidLoad()
XCTAssertEqual(viewController?.label?.text, "Hello, Qiita.")
}
初期のViewControllerにlabel
という名前のUILabelが存在するので、それのtextがHello, Qiita.
になっているはずというテストを書きました。
実際にテストを実行してみましょう。テストは⌘ + U
で実行できます。
テストが**失敗(RED)**してしまいました。では次に、テストが通るよう実装をしていきましょう。
##2. 最低限の実装をする
今回のテストは、viewController
がもつUILabel
のtext
が「Hello, Qiita.」となることだったので、そうなるように実装を変更してみましょう。
import UIKit
class ViewController: UIViewController {
var label: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
label?.center = CGPoint(
x: self.view.frame.width / 2,
y: self.view.frame.height / 2
)
label?.textAlignment = .center
label?.text = "Hello, World."
self.view.addSubview(label!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
現在のViewControllerクラスはこのような実装になっています。UILabel
のtextを変更してみましょう。
label?.text = "Hello, Qiita."
テストが**成功(Green)**しました!では最後にリファクタリングをしましょう。
##3. リファクタリング
リファクタリングでは、重複しているソースコードをまとめたり、視覚的にみやすくすることでメンテナンスを行いやすいようにします。
今回の例では特にリファクタする場所がないので、これで完了です。
#感想
iOSでのテスト駆動開発(TDD)はどうだったでしょうか。実装より先にテストを書くので慣れるまで大変だと思いますが、慣れればこちらの方が開発が安全かつスムーズに行えそうですね。
ちなみにUILabel
などのUIKitのテストを書く際にはUITest
というフレームワークを利用すると簡単にかけるらしいので、今後はそちらも試してみようと思います。
インターン自体の感想などはブログの方にアップしているので、興味のある方はぜひご覧ください。
Yahoo!iOS黒帯インターンでの思い出
#参考文献
今回のQiitaを書くにあたり、下記のサイトを参考にさせていただきました。ありがとうございました。
Apple Document - XCTest
和田卓人のテスト駆動開発講座
市場で勝ち続けるための品質とテストの技術 by 山下 真一郎
#サンプルファイル
今回使用したXcodeファイルはGithubにあげてあるので、ぜひ参考にしてください。
Github:サンプルファイル