読者です 読者をやめる 読者になる 読者になる

なんとなくRSpec使ってるやつダサい

minitest RSpec

先日、第5回若手Webエンジニア交流会でLTしてきました。
ビール飲んでピザつまみながらLTきいたりLTしたりするのカジュアルでいいですね。


というわけで、スライド公開します。
Testing Frameworkについてで、
「なんとなく、とりあえず、RSpec」みたいなのはダサいよねというお話

スライドの原稿

テストとかの話

矢口裕也
(@yayugu)

「みんなー
テスト書いてる?」

みたいなの飽きたよね

今日は
TDDとBDDとAgileとかの開発スタイル
と
テスト哲学の話を

しません

Testing Framework
の話をします

Testing Framework

大きく分けて2つ

xUnit
xSpec

xUnit

class TestInteger < UnitTest
  def test_add
    assert_equal(2, 1 + 1)
  end
end

xSpec

describe Integer
  context 'when add 2 numbers' do
    it 'should return sum' do
      2.should eq(1 + 1)
      expect(2).to eq(1 + 1)
    end
  end
end

ここで質問

どっちが好き?

xUnit

xSpec

ほうほう
なんで?

自分がなぜ
そのテストフレームワークを
好きか

答えられる?

みんなに言いたい

自分が使う
ツールのことを
もっと良く知ろう

フレームワークは
よく考えて
ちゃんと選ぼう

自分の話

さいきんRubyだと
minitest使ってる

iOSだと
SenTestingKit

何を考えて
これらを選んだのか

xUnit
xSpec

この2つを比較

※思想とかは考えない

比較方法

機能でそれぞれ2つの
パーツに分類してから比較

xUnit
 - test class
  class TestHoge, def test_hoge
 - assertion
  assert_equalとか

xSpec
 - behavior
  describe, context, it
 - expectation
  should, expect

(1)機能の違い
(2)表記の違い
(3)実装の違い

(1)機能の違い

assertionとexpectation
→同じもの

test classとbehavior
→振る舞いの階層化ができるか

(2)表記の違い

assertionと
expectationに
ついてのみ比較

参考フレームワーク:
Ruby
 - minitest
 - RSpec
Obj-C
 - SenTestingKit
 - Kiwi

Ruby

minitest

 assert_equal(2, 1 + 1)

RSpec
(should)

 (1 + 1).should eq(2)

RSpec
(expect)

 expect(1 + 1).to eq(2)

 assert_equal(2, 1 + 1)
 (1 + 1).should eq(2)
 expect(1 + 1).to eq(2)

Obj-C

SenTestingKit

 STAssertEquals(2, 1 + 1);

Kiwi
(should)

 [[foo should] equal:bar];

Kiwi
(expect)

[[theValue(1 + 1) should]
  equal:theValue(2)];

 STAssertEquals(2, 1 + 1)
 [[foo should] equal:bar];
 [[theValue(1 + 1) should] equal:theValue(2)];

表記の簡潔さ

assert > should > expect

(3)実装の違い

assert
の実装

global or
test classのインスタンスに
assert関数を定義

class UnitTest
  def assert_equal(expect, actual)
    if (expect == actual)
      puts '.'
    else
      puts('F')
    end
  end
end

expectation
の実装

2スタイルある
- should
- expect

should
の実装

RSpec

BasicObject.module_eval do
  def should(...)
    ...
  end
end

BasicObjectに
shouldを追加!!!

voodoo感ある

Kiwi

@interface NSObject (...)
- (void)should;
...
@end

NSObjectに
カテゴリとして
shouldを追加!!!

voodoo感ある

expect
の実装

RSpec

::RSpec::Matchers.module_eval do
  def should(...)
    ...
  end
end

BasicObjectオブジェクトを
汚染しないため
shouldよりmagic少ない

toやeqの実装は
面倒そう

Kiwi

#define theValue(expr) \
({ \
    ...
    [KWValue valueWithBytes:...
})

Kiwiも
同様

実装の健全さ

assert > expect > should

まとめ

-test class, behaviorの機能差
 階層化できるか
-assert, expectの機能差
  なし
-表記の簡潔さ
 assert > should > expect
-実装の健全さ
 assert > expect > should

使うべき
Testing Framework

A. 階層化が不要:
test class + assertion
→ xUnit

B. 必要:
階層構造 + assertion
→

minitest
Test::More subtest
など

を使うべき

サンプルコード

describe Integer
  context 'when add 2 numbers' do
    it 'should return sum' do
      assert_equal(2, 1 + 1)
    end
  end
end

ここに書いたのは
あくまで俺の考え

「なんとなく」
ではなくちゃんと考えて
Testing Framework
を選んで使おう

Happy testing!