0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails初学者】RSpecテストの書き方備忘録:実装寄りから仕様寄りへ

Last updated at Posted at 2025-10-05

はじめに

初学者の私は、RSpecでテストを書いていると、つい「動くかどうか」だけに目が行きがちになっていることに気づきました。
学習をしていく中で「テストは仕様書でもある」という考え方を知りました。
この記事では、実際にブログ投稿アプリを作りながら気づいたポイントを備忘録として残します。

学んだ3つのポイント

1. it の記述は「仕様」として読めるように

Before(実装寄り)

context "通知メールの初期状態" do
  let(:post) { create(:post, user: user, category: category, publish_date: Date.tomorrow, scheduled_at: "10:00") }
  
  it "is_sentがfalseである" do
    # ...
  end
end

After(仕様寄り)

context "通知メールの初期状態" do
  let(:post) { create(:post, user: user, category: category, publish_date: Date.tomorrow, scheduled_at: "10:00") }
  
  it "未送信として記録する" do
    # ...
  end
end

学んだこと

contextit のメッセージを実装寄りにせず、なるべく「仕様」寄りにするのが重要。
仕様は、エンジニアじゃない人/コードを知らない人が読んでも意味がわかるように

ポイント

  • is_sent という変数名ではなく、何が起こるのかを説明する
  • 非エンジニアでも理解できる表現にする
  • テストは「仕様書」としても機能すべき

2. メソッドのテストは describe でまとめる

Before(構造が不明瞭)

context "通知メールが作成された場合" do
  # create_notificationsメソッドのテスト内容
end

context "即時通知が作成される場合" do
  # さらにcreate_notificationsのテスト
end

After(メソッド単位で構造化)

describe '#create_notifications' do
  context '記事公開が明日の場合' do
    it '即時通知を作成する' do
      post.create_notifications
      
      # 実行後の期待値を書く
    end
  end
  
  context '記事公開が2日以上先の場合' do
    it '前日通知を作成する' do
      post.create_notifications
      
      # 実行後の期待値を書く
    end
  end
end

学んだこと

この部分は #create_notifications メソッドのテストになる。
そうであれば構造としては describe '#メソッド名' でまとめるのが自然。

ポイント

  • メソッドのテストは describe '#メソッド名' で囲む
  • どのメソッドをテストしているのか明確になる
  • テストの階層構造が整理される

3. context は条件分岐がある場合に使う

Before(不要なcontext)

describe '#create_notifications' do
  context "即時通知が作成される場合" do
    it "即時通知のタイトルが正しい" do
      # ...
    end
    
    it "即時通知の内容が正しい" do
      # ...
    end
  end
end

問題点: create_notifications メソッド内に分岐がないのに context を使っている

After(シンプルに)

describe '#create_notifications' do
  it '即時通知のタイトルが正しい' do
    post.create_notifications
    
    # 実行後の期待値を書く
  end

  it '即時通知の内容が正しい' do
    post.create_notifications
    
    # 実行後の期待値を書く
  end
end

学んだこと

context は、実装側(プロダクションコードと呼んだりする)で ifunless など実行に条件がある場合に使う。
一方 create_notifications メソッドの実装を見ると分岐は無いためにcontext 自体が不要。

ポイント

  • context は条件分岐に対応させる
  • 分岐がなければ it を直接並べる
  • 無駄なネストを避ける

実装に分岐がある場合の context の使い方

もし create_notifications に以下のような分岐があれば、context が有効

def create_notifications
  if publish_date == Date.tomorrow
    # 即時通知を作成
  else
    # 前日通知を作成
  end
end

この場合のテスト

describe '#create_notifications' do
  context '記事公開が明日の場合' do
    it '即時通知を作成する' do
      # ...
    end
  end
  
  context '記事公開が2日以上先の場合' do
    it '前日通知を作成する' do
      # ...
    end
  end
end

まとめ:良いテストの3原則

原則 説明
仕様として読める it は非エンジニアでも理解できる表現にする
構造を明確に メソッドのテストは describe '#メソッド名' で囲む
contextは分岐に対応 実装に条件分岐がある場合のみ context を使う

RSpecの基本構造

describe 'クラス名またはメソッド名' do
  context '特定の条件下では' do
    it '期待される振る舞いをする' do
      # テストコード
    end
  end
end
  • describe: 何をテストするか(クラス、メソッド)
  • context: どんな状況か(条件分岐)
  • it: 何が起こるべきか(仕様)

おわりに

テストコードは「将来の自分や他の開発者への説明書」。実装の詳細ではなく、何が保証されるべきかを明確に書くことで、保守性の高いテストになるようです。
学びを通じて、テストが単なる検証ツールではなく、仕様を伝えるドキュメントでもあること知りました。

実践する際のポイント

  • PRレビューで「itの説明が変数名っぽい」と言われたら、仕様寄り表現を意識してみる
  • describeやcontextを一度ツリー構造で整理してみる
  • 他の人のRSpecを読んで、どんな言葉で仕様が書かれているか観察する

参考資料


初学者のため、間違えていたらすいません。

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?