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を読むと、参考になることがたいてい書いてあるのですが、構造については見たことがないのでまとめてみました。
あれやこれやという議論のネタにしていただければ幸いです。
会社が賛助会に入っていたおかげで無料招待状を頂いたので、娘と二人で行ってきた。 昨年夏から娘がピアノを習い始めたので、プロの演奏を聴かせたいという趣旨。ちなみに、自分もオーケストラ鑑賞は初めて。
劇付随音楽『ペール・ギュント』 という、演奏だけでなく語りが含まれて、1つの物語になっていた。6歳の娘にはストーリーがよくわからず、音楽が楽しいという感じだった。 散々好き勝手やって遊び歩いておきながら、年老いて何に情熱を注ぐのかわからず故郷に戻って、若い時に捨てた恋人がそこで待っていてくれたなんて、待っていた方はどんな想いで待っていたのだろう。そして、ペールを看取った後、彼女はどうするのだろうか。普段は考えないようなことを色々と考えながら聴いていた*1。
これまでこういう音楽とか演劇とか食わず嫌いだったのだけど、面白いと感じる自分が良い発見だった。
*1 前半は寝てた。
当初はtDiary15周年パーティーに出席しようと思っていたのですが、東京フィルハーモニーオーケストラの無料チケットを頂いてしまったので、欠席してしまった。普段、日曜日は子どもたちと過ごす時間に必ず充てるようにしているというのもある。
自分がRubyを使い始めたのが高専5年生の時、つまり20歳からで、学部に編入してからレンタルサーバーでCGIを書いたりしてたと思う。当時はRubyがインストール済みのサーバーなんて、XREA.COMくらいしかなく、そこでtDiaryを起動したのを覚えている。しかし、これが何かのオペミスでふっ飛ばしてしまった。 その後、院生になってからは、WordPressに浮気してた。研究で使う言語はJavaで、研究のメモとかはHikiで記録してたり、データの集計や簡単なテキスト処理などでRubyはどこかしらで使っていた。 就職してからは、Rubyをメインで使うようになって、はてダでブログを書いたりしてた。 個人的にPaaSに興味を持ち始めて、Google App EngineにJRuby on Railsを動かしてみたりとかやっているうちに、Cloud FoundryでPaaS環境を社内に展開する部署に移った。なんとなしにtDiaryを調べてみたら、Herokuで動くとか書いてあったので、勢いでCloud Foundryでも動かすための手順を書いた。これが初めてtDiaryへのコミットとなった。VMwareがホスティングしているCloud Foundryが無料で使えたので、またtDiaryで日記を書き始めた。しかし、無料ホスティング終了のお知らせが来て、課金情報を登録しなかったせいで、インスタンスが消されてしまった。 その後、Redhatが提供しているPaaSのOpenShiftでtDiaryをセットアップして運用し始めた。OpenShiftは無料で提供してくれているのだが、Rubyのバージョンは古いままだし、rbenvでRubyをインストールしたあとにバージョンアップしようとすると、ディスクのquota値を越えてしまってインストールがこけたりと、面倒が多かった。そこで今年の初めに、Herokuへ引っ越しした。
ということで、途中間が空いたりはしたものの、tDiaryを10年くらい使ってきた。 ただ使うだけじゃなくて、GFMで書く際に発見したバグの修正とか、プラグインを書いたりとかコミットしてきた。なんというか、自分の考えを受け入れてくれるから愛着が湧いてくるように思う。そして、これからも使い続けるだろう。
15周年、おめでとうございます。そして、残り10年、何かできることからお手伝いしようかと思います。