超簡易な xUnit を Kotlin 入門しながら書く
Pixel 3 で写真撮るの楽しいです。久々の更新です(毎回言ってる気がする)。
Kotlin Advent Calendar 2018 5日目の記事です。
テスト駆動開発の本に書かれているプログラムを Kotlin で書いてみました。自分は Kotlin を触って日が浅いのですが、入門本を一冊読んでみたので何か書いてみようかと思ったのと、最近 「テスト駆動開発」という本を読んだので試しに xUnit 書いてみるかと。
クラスは、TestCaseTest, TestCase, WasRun, TestResult, TestSuite を作り、関数として getAttr 関数を作りました(機能的には getMethod という感じですが)。
Python では、オブジェクトの変数やメソッドを取り出す getAttr 関数があるのですが、Kotlin にはなさそうだったので、メソッドを取り出す関数を作りました。といってもただ Java のリフレクションを使っただけですが。以下のような感じです。
import java.lang.reflect.Method fun getAttr(obj: Any, method_name: String): Method { return obj.javaClass.getMethod(method_name) }
メソッドや関数の宣言の仕方はあとで書いてあるので飛ばしますが、上記のようにインポートすれば、Java のライブラリを使うことが出来ます。もっと上手いやり方がある気がするのですが本題じゃないので今回は上記のようにしました。
まず、基本クラスになる TestCase ですが、以下のようになります。
open class TestCase(var name: String) { open fun setUp() { } open fun tearDown() { } fun run(result: TestResult) { result.testStarted() setUp() try { val method = getAttr(this, this.name) method.invoke(this) } catch(e: Exception) { result.testFailed() } tearDown() } }
open class
ですが、Kotlin はデフォルトで継承が禁止されています。なので、継承させるために open
を指定あげます。class
は察しの通りクラスの定義を意味します。
次の TestCase(var name: String)
は、TestCase
がクラスの名前で、括弧内はクラスの持つ変数の宣言とプライマリコンストラクタの仮引数を表します。このように書くことで引数の値が宣言されている変数内に格納されます。ちなみに name は、テストしたいメソッド名を持ちます。
理解しやすいように書くと以下と同じ意味になります。
// open class TestCase constructor(name: String) でも同じ意味 open class TestCase(name: String) { var name: String init { this.name = name } }
これでコンストラクタと変数の初期化の仕方が分かりました。次は、メソッドです。
open fun setUp()
, open fun tearDown()
ですが、open
でオーバーライドを許可しているメソッドになります。
fun run()
メソッドですが、仮引数の TestResult
クラスは、テスト結果をカウントするクラスです。
run メソッドは、テストを実行するメソッドです。初めにテストの回数を増やし、テスト前に必要な初期化処理を行います(実際は継承先でオーバーライドされている処理が走ります)。その後、例外処理の try ブロック内でメソッドを実行します。失敗したときにプログラムが終了しないように catch 内で テストが失敗したことをカウントします。
Kotlin のアクセス修飾子ですが、デフォルトでは public
です。Java とは異なるので要注意です。
こちらが参考になると思います。 qiita.com
次に WasRun クラスを見ていきます。
class WasRun(name: String): TestCase(name) { var log: String init { log = "" } override fun setUp(): Unit { log = "setUp" } fun testMethod(): Unit { log = "${log} testMethod" } override fun tearDown() { log = "${log} tearDown" } fun testBrokenMethod() { throw Exception() } }
WasRun クラスは、テスト対象となるクラスです。ここでは、TestCase のテストを行いたいので、TestCase を継承しています。class WasRun(name: String): TestCase(name)
で使われているコロン(:)は、それのあとに書かれているクラスを継承することを意味しています。そして、コンストラクタに渡す引数として、WasRunクラスの変数を渡しています。
残りのメソッドは、オーバーライドをしていたり、テストに必要なメソッドを追加しています。testBrokenMethod()
内の throw Exception()
ですが、見ての通りエラーを発生させています。
また、"${log} testMethod"
のように文字列テンプレートを書くことが出来ます。
最後に、TestSuite クラスを見ていきます。
class TestSuite(val tests: MutableList<TestCase> = arrayListOf<TestCase>()) { var result: TestResult init { result = TestResult() } fun add(test: TestCase) { tests.add(test) } fun run(result: TestResult) { tests.forEach{ it.run(result) } } }
TestSuite クラスは、テストをまとめて行うためのクラスです。class TestSuite(val tests: MutableList<TestCase> = arrayListOf<TestCase>())
は、変数 tests
に引数がなければデフォルト引数として arrayListOf<TestCase>()
を入れるようにしています。
Kotlin の List についてはまだ詳しくないのですが、 readOnly と mutable なリストの二種類があります。簡単に紹介すると readOnly なリストは、中身を変えることができないリストで、 mutable なリストは、中身を変えることができるリストです。ただし、readOnly は以下のように書くことで中身を変えることが出来ます。
var list = mutableListOf(10, 20, 30) var list2: List<Int> = list list[0] = 33
リストについては以下が参考になると思います。
TestSuite では、様々なテストを tests
にまとめておきます。そして run メソッドによってリストの中身をすべて実行していきます。
fun run(result: TestResult) {
tests.forEach{
it.run(result)
}
}
簡単ですが、以上で Kotlin で作った xUnit の紹介を終わります。
Kotlin を使ってみた感想
書いてて楽しい言語だなと思いましたね。セミコロン必要ないですし、デフォルトで public になっていたり、継承がコロンだけで済んだり、また、継承もデフォルトで禁止されているのは良いなと思いました。null を許容しないのもいいですね。
Kotlin は、短く書けるけど何でもかんでも短くはしないというか、書きやすいと読みやすいのバランスが良いという感じがしました。
ぜひ仕事で使ってみたいので、修得してサーバやスマフォ開発で使いたいですね。
参考
入門するために読んだ本です。これは何か言語を知っていれば短時間で Kotlin にどんな機能があるのか把握できるので、とてもよかったです(何か言語を使ったことある前提)。
速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ
- 作者: 山田祥寛
- 出版社/メーカー: WINGSプロジェクト
- 発売日: 2018/09/26
- メディア: Kindle版
- この商品を含むブログを見る
テスト駆動開発の本です。改訂版ですが、とても翻訳のクオリティが高く、言語も今に合わせて翻訳者が書き直してくれています。しかも付録として歴史的な話も載っています。さらに値段も安いです。すごいです…。
- 作者: Kent Beck,和田卓人
- 出版社/メーカー: オーム社
- 発売日: 2017/10/14
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
以下もおすすめらしいです。
- 作者: Dmitry Jemerov,Svetlana Isakova,長澤太郎,藤原聖,山本純平,yy_yank
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/10/31
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
記事内のコード
おれ、今の仕事納めたら Kotlin 勉強するんだ……