Rubyが好きなプログラマーの日記。日々の生活、開発に関するメモとか考えとか。
自分が、真面目にテストコードを書きはじめて、だいたい4年くらい経ちました。 その間、いろんなgemとか、アプリケーションのソースを読んできたけど、
見やすい構造があるなぁ
と思ったので、自分なりに見やすいと思えるものを、ここに書いてみる。
実装本体だけでなく、テストコード自体の読みやすさも大切だと思う。
ディレクトリの階層、命名は、実装に合わせる。例えば、プロジェクトのルートディレクトリ直下で、
project/
bin/
lib/
my_app/
implementation.rb
というソースコードがあった場合、そのテストは、
project/
spec/
my_app/
implementation_spec.rb
とする。 これは、
テストは仕様書である。
という考えに基づいて、実装とそれに対応する仕様が書かれている場所を類推しやすくするためである。
spec
ファイルで取り扱うべきクラス、またはモジュールは1つのみ実装においても、もともと1つのファイルに含まれている対象となるクラスはなるべく少ない方が分かりやすい。 行数が少なく、他に比べて関連性の高い複数のクラスまたはモジュールが1つのファイル内に納められることもあるが、この場合は、1つ前の規約を優先し、ファイル内。
describe
で対象となるクラスまたはモジュールを指定する。例えば、my_app/implementation.rb
に、
class MyApp::Implementation
end
spec/my_app/implementation_spec.rb
内では、
describe MyApp::Implementation do
# examples
end
のように書く。上述の通り、複数のクラスまたはモジュールが1つのファイルに実装されている場合、
describe MyApp::Implementation do
# examples
end
describe MyApp::Implementation::InnerModule do
# examples
end
のように実装する。
describe
の内側には対象となるメソッドを書く。以下のような実装にあるそれぞれのメソッドについて単体テストを書くとき、
class MyApp::Implementation
def self.bar
end
def foo(arg1, arg2=nil)
end
end
対象のメソッドごとにdescribe
で宣言する。
describe MyApp::Implementation do
describe '.bar' do
end
describe '#foo' do
end
end
複数の条件をごとにテストする際には、context
を使いそれぞれの条件について宣言し、before
を用いて前提条件を表現するコードを記述する。
describe MyApp::Implementation do
describe '#foo' do
let(:myapp) { MyApp::Implementation.new }
context 'When given 1 arg' do
before do
myapp.foo('str')
end
end
context 'When given 2 args' do
before do
myapp.foo('str', 1234)
end
end
end
end
describe
ないし context
の内部は、
let
または let!
before
、after
または around
subject
it
またはspecify
describe
または context
の順で記述する。
before
、after
、around
の順に、:all
、そして:each
の順で記述する。subject
を用いる場合はit
を、それ以外ではspecify
を使う。describe MyApp::Implementation do
describe '#foo' do
let(:args1) { [:aaa] }
let(:args2) { [:aaa, 1234] }
subject { MyApp::Implementation.new }
its(:foo) { should be_present }
context 'Given 1 argument' do
end
context 'Given 2 arguments' do
end
end
悩んだらBetter Specsを読むと、参考になることがたいてい書いてあるのですが、構造については見たことがないのでまとめてみました。
あれやこれやという議論のネタにしていただければ幸いです。