37
35

More than 3 years have passed since last update.

【RSpec】System Specが動作するRails+Docker開発環境を構築する

Last updated at Posted at 2020-03-10

はじめに

Rspec3.7以降で実装された"System Spec"を動作できるRails+Docker環境の作り方をまとめました。

基本コピペで進められるように書きましたので、初学者の方であっても「まず動く」状態まで持っていけると思います。

この記事では、Docker、docker-composeがすでにインストールされた状態からスタートします。私は、自PC(Mac)のホストOSに「Docker for Mac」をインストールしています。

著者動作環境における、Docker、docker-composeのバージョンは以下の通りです。

$ docker --version
Docker version 19.03.5, build 633a0ea
$ docker-compose -v
docker-compose version 1.25.4, build 8d51620a

DockerでのRails環境の構築

まずは、Docker公式が用意してくれているRals用のクイックスタート「Quickstart: Compose and Rails」をベースに、Railsが動作するDocker環境を作成していきます。

一部、公式のファイル内容に変更を加えていますので、ご注意ください。

早速始めていきましょう。作業ディレクトリ用意し、cdで移動します。

$ mkdir sample_app
$ cd sample_app

Quickstartに則り、sample_app内に下記5ファイルを作成します。

/sample_app
$ touch Dockerfile docker-compose.yml Gemfile Gemfile.lock entrypoint.sh
ディレクトリ構造
/sample_app
 ├── Dockerfile
 ├── Gemfile
 ├── Gemfile.lock
 ├── entrypoint.sh
 └── docker-compose.yml

各ファイルを下記の通り編集します。5ファイルのうち、docker-compose.yml以外は、Quickstart公式のコピペです。vim等、お好きなテキストエディタをお使いください。

Dockerfile
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
Gemfile.lock
(空のまま)
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      - "POSTGRES_USER=xxxx" # 追記
      - "POSTGRES_PASSWORD=xxxx" # 追記
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      - "SELENIUM_DRIVER_URL=http://selenium_chrome:4444/wd/hub" # 追記
  selenium_chrome:
    image: selenium/standalone-chrome-debug # 追記

上記5ファイルのうち、docker-compose.ymlのみ、編集で手を加えています。具体的には、
・postgresにユーザー名、パスワードを指定
・System Specを動作させるためのコンテナイメージ「selenium/standalone-chrome-debug」を追加

ファイルを作成したら、Railsアプリを新規作成します。

$ docker-compose run web rails new . --force --no-deps --database=postgresql
/sample_app
$ ls
Dockerfile              README.md               bin                     db                      lib                     public                  tmp
Gemfile                 Rakefile                config                  docker-compose.yml      log                     storage                 vendor
Gemfile.lock            app                     config.ru               entrypoint.sh           package.json            test

rails newに伴い、Gemfileにデフォルトのgemがインストールされました。

Gemfileに編集を加えます。具体的には、

・"rspec-rails"を追加
・"chromedriver-helper"を削除

Gemfile

# 省略

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails' # 追記
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of chromedriver to run system tests with Chrome
  # gem 'chromedriver-helper' # 削除
end

#省略

Gemfileを更新したため、再ビルドします。

$ docker-compose build

これで、新しいGemfileでbundle installが実行されました。

続いて、configディレクトリ内のdatabase.ymlを編集します。

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: xxxx
  password: xxxx
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test

DBを作成します。

$ docker-compose run web rails db:create
Starting sample_app_db_1 ... done
Created database 'myapp_development'
Created database 'myapp_test'

コンテナを起動します。このタイミングで、selenium/standalone-chrome-debugのプルが実行されます。

$ docker-compose up -d
Pulling selenium_chrome (selenium/standalone-chrome-debug:)...
latest: Pulling from selenium/standalone-chrome-debug
.
.
.

イメージプルが終了しましたら、docker-composeが正常に立ち上がっているか、確認してみましょう。

$ docker-compose ps
            Name                           Command               State           Ports         
-----------------------------------------------------------------------------------------------
sample_app_db_1                docker-entrypoint.sh postgres    Up      5432/tcp              
sample_app_selenium_chrome_1   /opt/bin/entry_point.sh          Up      4444/tcp, 5900/tcp    
sample_app_web_1               entrypoint.sh bash -c rm - ...   Up      0.0.0.0:3000->3000/tcp

web,db,selenium_chromeの3つが立ち上がっていれば、OKです。ついでに、http://localhost:3000 にアクセスし、いつもの「Yay! You’re on Rails!」が表示されているか、確認しましょう。

また、RSpecが正確にインストールされているかも確認してみましょう。

$ docker-compose run web rspec -v
Starting sampleApp_db_1 ... done
RSpec 3.9
  - rspec-core 3.9.1
  - rspec-expectations 3.9.0
  - rspec-mocks 3.9.1
  - rspec-rails 3.9.0
  - rspec-support 3.9.2

各バージョンは状況により異なるかと思いますが、RSpec 3.7以上のバージョンであれば、System Specを動作させることができます。

RSpecの初期設定

無事、必要なgemが揃った状態のDockerコンテナを用意できたので、ここからは中身の諸々の設定をいじっていきます。

まず、Railsにデフォルトで配置されているtestディレクトリは使用しないため、削除してしまいましょう。

$ rm -rf test

RSpecをインストールします。

$ docker-compose run web rails generate rspec:install

これにより、以下のディレクトリ構造に対して、計3ファイルが生成・配置されます。

ディレクトリ構造
/sample_app
  ├── .rspec
  └── spec
       ├── rails_helper.rb
       └── spec_helper.rb

.rpsecファイルを編集します。2行目のコードを追記してください。これにより、テスト結果の表示形式が変更されます。

.rspec
--require spec_helper
--format documentation

デフォルトでは、”失敗したテスト”のみがターミナル上に出力されるのですが、この変更を行うことにより、”成功・失敗両方のテスト”の結果を出力してくれるようになります。必須ではありませんが、設定しておくことをオススメします。

続いて、spec/rails_helper.rbについて、25行目あたりに書かれている下記コードのコメントアウトを外してください。

spec/rails_helper.rb
# 省略

Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

# 省略

これにより、後ほど定義するCapybara用の設定ファイルを読み込めるようになります。

specファイルの自動生成機能OFF

デフォルトでは、controllerやviewを作成したタイミングで、対応するspecファイル(=テストコードを書くためのファイル)が自動生成されます。

今回は初学者にとっての混乱を防ぐため、自動生成はOFFにしておきます。config/application.rbに下記コードを追加します。

config/application.rb
equire_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Myapp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.

    ### 追記 ######################################
    config.generators do |g|
      g.test_framework :rspec,
                       view_specs: false,
                       helper_specs: false,
                       controller_specs: false,
                       routing_specs: false,
                       request_specs: false
    end
    ##############################################
  end
end

Capybaraの初期設定

Capybaraに設定を加えるため、capybara.rbファイルを作ります。

$ mkdir spec/support
$ touch spec/support/capybara.rb
spec/support/capybara.rb
require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selenium, using: :headless_chrome, options: {
      browser: :remote,
      url: ENV.fetch("SELENIUM_DRIVER_URL"),
      desired_capabilities: :chrome
    }
    Capybara.server_host = 'web'
    Capybara.app_host='http://web'
  end
end

これで、SystemSpecが動作する環境が整いました。

System Spec実践

それでは実際に、静的ページを用いてSystemSpecを使用してみましょう。

今回は、

・rootページにアクセスし、"Hello World!"が表示されていることを検証
・rootページに、"Helpページ"へのリンクが置かれていることを検証
・リンク先のHelpページに、"This is the help page."が表示されていることを検証

という流れのテストを書いてみたいと思います。

下準備として、home,helpを持ったStaticPagesコントローラーを作成します。

$ docker-compose run web rails generate controller StaticPages home help

ルートとビューをいじります。

config/routes.rb
Rails.application.routes.draw do
  root 'static_pages#home'
   get '/help', to: 'static_pages#help'
end
app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p><%= link_to "Help", help_path %></p>
app/views/static_pages/help.html.erb
<h1>This is the help page.</h1>

下準備が終わったため、specファイルを書いていきます。specディレクトリ下にsystemディレクトリを作成し、その中に"homes_spec.rb"を配置します。

$ mkdir spec/system
$ touch spec/system/homes_spec.rb

spec/system/homes_spec.rbを編集します。

spec/system/homes_spec.rb
require 'rails_helper'

RSpec.describe 'Home', type: :system do
  it 'shows greeting' do
    # root_pathへアクセス
    visit root_path
    # ページ内に'Hello World!'が含まれているかを検証
    expect(page).to have_content 'Hello World!'
    # 'Help'文字列をクリック
    click_on 'Help'
    # ページ内に'This is the help page.'が含まれているかを検証
    expect(page).to have_content 'This is the help page.'
  end
end

いよいよ動かします!今回用意した環境でSystem Specを動かすためには、webコンテナ内に入る必要があります。

$ docker-compose exec web bash

rspecは、"rails spec"コマンドで実行できます。

webコンテナ内
$ rails spec
/usr/local/bin/ruby -I/usr/local/bundle/gems/rspec-core-3.9.1/lib:/usr/local/bundle/gems/rspec-support-3.9.2/lib /usr/local/bundle/gems/rspec-core-3.9.1/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb

Home
Capybara starting Puma...
* Version 3.12.4 , codename: Llamas in Pajamas
* Min threads: 0, max threads: 4
* Listening on tcp://web:45873
  shows greeting

Finished in 2.33 seconds (files took 8.35 seconds to load)
1 example, 0 failures

無事、テストが通ればOKです!!

スクリーンショット保存機能

ちなみにですが、System Specには、「失敗時の画面をスクリーンショットで自動保存する」という便利機能があります。

ビューをいじって、わざとテストを失敗させてみましょう。

app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p><%= link_to "Hel", help_path %></p>  # "Help"をタイポしてしまったケース
webコンテナ内
$ rails spec

.
.
.

Home
Capybara starting Puma...
* Version 3.12.4 , codename: Llamas in Pajamas
* Min threads: 0, max threads: 4
* Listening on tcp://web:44173
  shows greeting (FAILED - 1)

Failures:

  1) Home shows greeting
     Failure/Error: click_on 'Help'

     Capybara::ElementNotFound:
       Unable to find link or button "Help"

     [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_home_shows_greeting_612.png
.
.
.

「'Help'が見つかりません!」とメッセージが出され、tmp/screenshotsにエラーが発生したタイミングでのブラウザ画面が保存されています。

failures_r_spec_example_groups_home_shows_greeting_612.png

"Help"と書いたつもりのところが"Hel"になってしまっているのが、確認できます。

最後に

以上です!不明な点、間違っている点などがありましたら、私のTwitter(@ddpmntcpbr)のDMまで連絡頂けると幸いです。

37
35
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
37
35