0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rspecでのユニットテスト

Posted at

100度超えサウナでないと満足できない、プレイライフのサウナエンジニアの合原です。

当社では、現在、Ruby on Railsを用いてサービス開発をしています。また、Rspecを使ったテストも普段から行なっています。

そこで、今回はテストの効用、ユニットテストの重要性and少しだけサンプルを示してみます。

対象読者

  • テストの効用がよくわからない人
  • ユニットテストを書いたことがない人
  • ユニットテストの効果がよくわからない人
  • 効果的なユニットテストを書くにはどうすればよいか学びたい人
  • プレイライフではエンジニアリングをしているのか興味がある方

Rspecとは

こちらは言わずと知れた、ポピュラーなテストフレームワーク。
構文には一種のくせ(?)あるため、敬遠する人もいるが、一度覚えると、柔軟なテストができます。

Rspecのメリット

  • Rubyで最もポピュラーなテスティングフレームワーク
  • メタ視点でのテストが書けるため、テストコードが自然言語っぽくなる
  • ユニットテストに限らず、結合テストやブラウザテストなどにも使える

Rspecデメリット

  • 一定の学習コストがある

反面、一度覚えれば、より柔軟なテストが可能となる。

なぜテストを書くのか

大きくは、以下の3つ。

  • 改修時など、テストが失敗することで漏れや変更点が明確になり、デグレを防げる
  • テスト自体が仕様となるため、コードの理解がしやすくなる
  • コードの品質を上げられる

ユニット(単体)テストとは

ユニットテストとは、ソースコードの個々のユニット、すなわち、1つ以上のコンピュータプログラムモジュールが使用に適しているかどうかを決定するために、関連する制御データ、使用手順、操作手順とともにテストする手法である[1]。ユニットとはアプリケーションのテスト可能な最小の部品単位である、と直観的にとらえることができる

言い換えると、メソッドやクラスと言った単位で、想定された仕様どおりに動作しているかを検証するテスト。

なぜユニットテストが重要なのか

基本的に、アプリケーションは各種モジュールの束でできているため、各モジュール単位に分解して、それぞれをの動作を検証(テスト)することは不可欠になります。
これができていると、さらに上位の各機能の結合テストはさらに容易になる。
自ずと、アプリケーションのテスト網羅性は高めることができます。

基本的な考え方

ユニットテストでは、クラスやメソッドを最小処理単位として扱い、引数を処理した「結果」と、想定される「期待値」(これを振る舞いと言う)の2つを検証(比較)します。

ここで、以下のような引く数を受け取り1を加算するだけのメソッドをテストすることを考えてみます。


class Calc
  def add(arg)
     arg + 1
  end
end

1.テストケースを想定する

上記のメソッドからテストケースを想定すると、大きくは以下の2つのケースが考えられます。

  1. 引数がnilの場合
  2. 引数が正常な数値の場合
  3. 引数が文字列等の場合

rspecで書くと..


RSpec.describe Calc, type: :model do # テスト対象となるクラス
  describe '#add' do #テスト対象となるメソッド
    context '引数がnilの場合' do
      [ここに具体的なテスト内容]
    end
    context '引数が正常な数値の場合' do
      [ここに具体的なテスト内容]
    end
    context '引数が不正な値(文字列等)の場合' do
      [ここに具体的なテスト内容]
    end
  end
end

※ contextの箇所は英語でも日本語でもわかればいいと思います。テストの本質とは全く関係ないため。

こうすることで

  • メソッドの振る舞いが明確になる
  • テストを見るだけで、このメソッドの動作がわかる
  • 仮にレビュアーであれば、ここを見るだけで、実は他にも動作ケースがありうるのであればテストケース漏れを指摘しやすくもなる
  • 仮にプロダクション環境にデプロイ後でも、ここを見れば漏れが明確になり、修正が容易になる(メンテコスト下がる)
  • 既存の振る舞いが明確なので、リファクタリングもしやすい

2. 実際のテストコード

最終的なコードは下記の通り。
※細かいrspecの文法については割愛。


RSpec.describe Calc, type: :model do # テスト対象となるクラス
  describe '#add' do #テスト対象となるメソッド
    subject { Calc.new.add(arg)}
    context '引数がnilの場合' do
      expect { subject }.to raise_error NoMethodError
    end
    context '引数が正常な数値の場合' do
      let(:arg) { 1 }
      it { is_expected.to eq 2 }
    end
    context '引数が不正な値(文字列等)の場合' do
      let(:arg) { 'a' }
      expect { subject }.to raise_error TypeError
    end
  end
end

まとめ

と言うわけで、あくまで簡易な例で一気に説明しましたが、ユニットテストを行うことで、

  • コードの品質向上
  • 将来的なメンテコストの下げられる(場合もある)

といったことが望めるのは少しおわかりいただけたか(?)と思います。
もちろん、Rspecに慣れないといけないと言った面もあります。
これからしっかりテストコードを書いていきたいと言う方に少しでも、お役に立てたら幸いです。

また、当社では、テストを軽視することなく、何よりもスピーディなサービス開発を実現することにも、果敢に挑戦しています。気になる方は、ぜひ、こちらから。

あわせて読みたい

RSpecの公式ドキュメント
オブジェクト指向設計実践ガイド

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?