ソフトウェア・テストは大変です

ソフトウェアとか書いたけどそんな大層なものでなく,自分用のToDoツールをRubyで書いています. 僕は,テスト文化のない,オープンでない会社育ちで,テストを書くことはほぼありませんでした.今回まじめにあたってみての感想を書いてみます.

テストコードを含む開発の工数

うまく開発できた場合,プロダクションコードの2倍から3倍かかる具合でした.コードの量も,偶然かもしれないけれど,同じ比率になりました. しかし,後述するメリットが大きいため,テストコードを開発することは今後も続けていきたいと思っています.

メリット

TDDでは,「RED!GREEN!リファクタリング!」繰り返し叫び続けます.この作業が結構気持ちいいです.リズムができ開発が捗ったと思います.

しかし,今回はTDDしたわけではないです.プロダクションコードを書いてテストコードを書いてと開発しています. TDDするか,そうしないかは,論争があると思いますし,僕もどちらが良いとも思えません.ある程度コードを書くのが慣れている人は後者の方が効率がよいと思います.新人研修などではTDDは良いかもしれません.

コードが綺麗になるメリットも捨てがたいです.

最大のメリットはテストがいつでも誰でもできることでしょう. 無意味にテストを走らせてGREENを見るのでも,精神衛生上良いです.

デメリット

先述の工数の問題は確かにあるのですが,メリットで書いたようにテストがいつでもできることを考えると大きな問題では無い気がします.

最大の問題は「テストコードどれだけ書くの?問題」です.正直なところテストコードは無限に書けるでしょう.そしてどれだけ書いたところでテストコードのメンテナンスも発生しますので逆効果です.

「テストコードは仕様を書くがごとく」+αくらいが調度良いところです.基本は,代表値,境界値,エラー値でしょうか.

Rubyでのユニットテスト

Rubyでのユニットテスト・スイートは,Ruby標準添付のTestUnitを使用しました. ActiveRecordを使っているのでRSpecも考えはしたのですが難しそうでやめました. アサーションは今のところ,「assert_equal」「assert_raise」しか使っていないです. 以下,サンプルコード.

require 'test/unit'

class StandardTest < Test::Unit::TestCase

  test "add(1 + 2) == 3" do
    assert_equal(3, add(1, 2))
  end

  sub_test_case "div" do
    test "div(20, 4) == 5" do
      assert_equal(5, div(20, 4))
    end

    test "div(20, 0) => raise ArgumentError" do
      assert_raise(ArgumentError) do
        div(20, 0)
      end
    end
  end

end

def add(a, b)
  a + b
end

def div(a, b)
  if b == 0
    raise ArgumentError, "zero div error"
  end
  a / b
end