Rails4

helper typeを利用して、ModuleのRSpecの書き方をまとめてみました

More than 3 years have passed since last update.

はじめに

Railsのアプリの1つの機能としていくつかのサイトを巡回するクローラーを開発しており、

  • HTTPクライアントの機能を利用してサイトにアクセスする機能
  • (全部ではないけど)HTMLの要素をスクレイピングする機能

あたりは共通化できそうなのでそこだけモジュール化しようと思って実装を進めていきたのですが、肝心のモジュールに対するRSpecの書き方を知らなかったので、調べたことをまとめておきました

app/workers配下にクローラーを配置して利用することを想定してディレクトリ構成はこのようになります

app/workers
├── core_worker.rb
├── crawler
│   ├── searchable.rb
│   ├── site_a.rb
│   ├── site_b.rb
│   └── site_c.rb

ちなみに想定するクローラーの処理としてはこんな感じをイメージしてます

  • 定期的ににcore_worker.rbが実行される
    • 1日1回とか
  • core_workerがsite_a.rb、site_b.rb、site_c.rbのそれぞれのクラスの初期化&クローリングを実行
  • クローリングする時に、site_a.rb、site_b.rb、site_c.rbそれぞれで共通利用する処理をsearchable.rbにまとめる

手元の開発環境

  • Mac OS X 10.8.5
  • Ruby 2.2.2
    • rbenv利用してインストール
  • Rails 4.2
  • rspec 3.3.0

モジュールに対するRSpecはいくつかアプローチがありそう

最初はRails4のconcernsなmoduleのテストをrspecで書く方法の情報にいきついたのですが、その後StackOverflowのTesting modules in rspecを見てたら参考になる書き方が紹介されてました。

ダミーとなるクラスでそのモジュールをincludeするようなやり方などいくつか紹介されてるのですが、個人的には

describe SomeModule, type: :helper do
  # 省略
end

というhelper typeを利用した書き方が理解しやすく、Helper specの情報と合わせて読んだらイメージした形で書けたのでこの方針でいくことにしました

実際にどういう形になったのか?

まず、RSpecの方ですが、spec/workers/crawler/searchable_spec.rbというファイルを作って以下のように書きました。

require 'rest-client'
require 'nokogiri'
describe Crawler::Searchable, type: :helper do
  describe '#page_source' do
    let(:valid_url) { 'http://qiita.com' }
    let(:invalid_url) { 'http://test' }
    context '存在するサイトのURLを指定した場合' do
      it 'スクレイピングの結果が得られる' do
        doc = helper.page_source(valid_url)
        expect(doc.present?).to eq true
      end
    end
    context '存在しないサイトのURLを指定した場合' do
      it 'falseが返る' do
        doc = helper.page_source(invalid_url)
        expect(doc.present?).to eq false
      end
    end
  end
end

上記のRSpecにパスするようにapp/workers/crawler/searchable.rbをこのように実装しました。

module Crawler
  module Searchable
    def page_source(url)
      return false if url.empty?
      begin
        return RestClient.get(url)
      rescue => e
        return false
      end
    end
  end
end

RSpecの実行結果も貼っておきます

./bin/rspec spec/workers/crawler/searchable_spec.rb
Crawler::Searchable
  #page_source
    存在するサイトのURLを指定した場合
      スクレイピングの結果が得られる
    存在しないサイトのURLを指定した場合
      falseが返る

Finished in 0.2259 seconds (files took 4.12 seconds to load)
2 examples, 0 failures

※本文の内容と直接関連がないですが、RSpecの実行結果がドキュメント形式で表示されるように.rspecを以下のようにしてます。
ここの記述内容がほかの人に理解しやすい形になっているかどうか気にすることで、describe/contextの使い分けが妥当かどうか気づけるからです。

--color
--require spec_helper
--format documentation