LoginSignup
1
0

More than 5 years have passed since last update.

Docker + Rails + MySQL + Vue で Todo アプリ作成 〜その2 RSpec 〜

Last updated at Posted at 2019-03-02

おさらい

最終目標 : trello
前回 : seed データを投入して、ルートページと index ページで seed データの一覧表示できるところまで

その2 の目標

1.前回の分のテストを書く

1. なぜテストを書くのか

なぜなんだ

→ 安全だからです。
あー、とっても答えになってないですね
そう言う時は先生に聞きます

Rails Tutorial が僕の基本的な先生です。(10章までやった)
先生は テスト駆動開発(TDD) を推奨していました

テスト駆動開発とはなんぞや

  1. テストを先に書く
  2. もちろん失敗する
  3. 失敗しないように実装していく

だいたいこんな感じ。

なんでそんなことすんの?

あれ?なんでそんなことするの?
なぜなんだ(本日2回目)
ということで一旦ググる

良さげな記事を発見
【初心者向け】テスト駆動開発とRspecについて調べてみた
ありがとうございます。勉強になります。

2. インストールする

だいたいわかったので
とりあえず RSpec をインストールする。。。

Gemfile
# ~~省略~~
group :development, :test do
  gem 'rspec-rails'
end

参考:RSpec 公式

Gemfile を更新したらば、web コンテナで gem をインストールしていく

web
# bundle install

# rspec -v
RSpec 3.8
  - rspec-core 3.8.0
  - rspec-expectations 3.8.2
  - rspec-mocks 3.8.0
  - rspec-rails 3.8.2
  - rspec-support 3.8.0

# rails  g rspec:install
Running via Spring preloader in process 495
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb

入ってますね。

3. どんなテストを書くか

/ (ルートページ) と /index にアクセスした際に
seed に入れたデータが全て取得できることを確認する。

必要なテストは2つ
1. / ルートページにアクセスした際に、 期待するデータの全てが取得できること
2. /index にアクセスした際に、期待しt(ry

こんなもんかな
まだしなきゃいけないことあるなら思いついた時にやります。
とりあえず今回はこの二つ

4. 作業開始(準備)

まずはテストファイルを作成します。

$ touch spec/controllers/index_page_spec.rb

今後 Contoroller のテストを行うものは全て spec/controllers/ に入れようと思います。

memo

hogehoge_spec.rb_spec これ

書かなくてもテストは実行できるんです。
じゃあなんで書くのかと言うと
bundle exec rspec でテストを実行した時に _spec がついてるファイルを
わざわざ指定しなくても、まとめて実行できるんです。

つまり

$ bundle exec rspec spec/hoge/hoge.rb
$ bundle exec rspec spec/fuga/fuga.rb
$ bundle exec rspec spec/piyo.rb
$ bundle exec rspec poyo.rb

と、しないといけないところを
お尻に _spec とつけるだけで

$ bundle exec rspec

上記のをまとめて実行できるようになるんですね、すごい!
めっちゃ便利なので積極的にお尻にスペックをつけましょう。

(この認識に誤りがあったら教えてください。mm)


それでは作業に戻ります。

spec/controllers/index_page_spec.rb
RSpec.describe 'TasksController' do
  context 'show index page' do
    it 'show task list on root page' do
    end

    it 'show task list on index page' do
    end
  end
end

TasksController を文字列にした理由

web
# bundle exec rspec 
..

Finished in 0.00874 seconds (files took 0.13328 seconds to load)
2 examples, 0 failures

何も書いてないので、当然グリーンになります。

公式 に書いてあった書き方を真似てみました。
一行目で、君は RSpec の仲間だよ〜って教えてあげてるんだと思います。
んー、ちょっと微妙な理解っぽいので、もう少し調べてみます
公式を読み進めてみると。。

image.png

Controller のテストの書き方かな? リンクがありましたね
こちら
いいぞ、すごいそれっぽいぞ

Controller specs are marked by :type => :controller or if you have set
config.infer_spec_type_from_file_location! by placing them in spec/controllers.

コントローラーのテストだよーって教えてあげるためには、どこかに :type => :controller を書くか spec/controllers/ に配置する必要があるみたいです。
コントローラーのテストだよって教えてあげないといけないんですね

render_views というものがあるみたい
僕のは こちら に該当したので、書き方を変えます。

spec/controllers/index_page_spec.rb
require 'rails_helper'

RSpec.describe TasksController do
  render_views

  context 'show index' do
    it 'show task list on root page' do
    end

    it 'show task list on index page' do
    end
  end
end

type ~~ を書くように書いてありましたが、さっき spec/controllers/ 配下なら書かなくていいよとも書いてあったので書きません。
あと、ここではコントローラーを' 'で囲わなくても大丈夫だったので、こうします

require 'rails-helper' ????
...誰ですか???!!!

〜回想〜
$ bundle install
$ rails g rspec:install
Running via Spring preloader in process 495
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb

いた...。
いた!!
いました。

どうやら このヘルパーを require しないと render_views が使えないみたいです。

オマケがありました
おそらく Rails のヘルパーを使う事を明記したので、Rails で作成したコントローラーが文字列でなくても認識してくれたのかなって思います。
書かなくていいことは書きたくないので ' ' 消しました

web
# bundle exec rspec 
..

Finished in 0.04538 seconds (files took 7.39 seconds to load)
2 examples, 0 failures

は??なんか7秒もかかりました。
ふざけんな、なんでじゃ、なんもテストしとらんのに!

ちょっとテストの時間がかかるのはストレスですが、一旦後回しにします。
テストの時間がかかる事を対策することに時間がかかりそうなので

5. 作業開始(本当に)

ちょっと予想外に調べるものが多かったので、章分けしました。
それでは気を取り直してやっていきますか
(もう結構しんどい、こんなややこしいの...?)

とりあえず、index を開いてほしい。
公式をみるとそれっぽいことが書いてあった。

spec/controllers/index_page_spec.rb
~~
it 'show task list on index page' do
  get :index
end
~~
web
# bundle exec rspec 
..

Finished in 0.48295 seconds (files took 5.18 seconds to load)
2 examples, 0 failures

いい感じ、なぜか時間も短くなってるし、なげえけどな

spec/controllers/index_page_spec.rb
~~
it 'show task list on index page' do
  get :index
  expect(response).to render_template('index')
  expect(response.body).to eq 'task 001 : hogehoge'
end
~~
web
# bundle exec rspec 
.F

Failures:

  1) TasksController show index show task list on index page
     Failure/Error: expect(response).to render_template('index')

     NoMethodError:
       assert_template has been extracted to a gem. To continue using it,
               add `gem 'rails-controller-testing'` to your Gemfile.
     # ./spec/controllers/index_page_spec.rb:12:in `block (3 levels) in <top (required)>'

Finished in 0.48037 seconds (files took 5.57 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/controllers/index_page_spec.rb:10 # TasksController show index show task list on index page

なんか Gem がないよって怒ってますね
どうやら assert_template を使うには rails-controller-testing という Gem が必要みたい
は?なにこいつめっちゃ親切にエラーを出すじゃないか、やさしい

5.1 Gem install

インストールは公式を見た方が最新の情報が書いてあったりするので、安全だと思っています。
ので
公式 を見ます。
Gemfile のどこに書いてもいいみたい、けどまあ RSpec を使う環境でしか使わないし、一緒の所に書いておきましょうか。

Gemfile
group :development, :test do
  gem 'rspec-rails'
  gem 'rails-controller-testing'
end
web
# bundle

あっ、へ〜、公式の install 方法に書いてあったので真似たのですが bundle installbundle と省略できるんですね、便利。
よく使うからきっと用意されたのでしょう、楽チンなので覚えました

web
  1) TasksController show index show task list on index page
     Failure/Error: expect(response.body).to eq 'task 001 : hogehoge'

       expected: "task 001 : hogehoge"
            got: "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Myapp</title>\n    \n    \n\n    <link rel=\"styleshee...\"></script>\n  </head>\n\n  <body>\n    <h1>Your Tasks</h1>\n\n<ul>\n</ul>\n\n  </body>\n</html>\n"

       (compared using ==)

       Diff:
       @@ -1,2 +1,20 @@
       -task 001 : hogehoge
       +<!DOCTYPE html>
       +<html>
       +  <head>
       +    <title>Myapp</title>
       +    
       +    
       +
       +    <link rel="stylesheet" media="all" href="/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css" data-turbolinks-track="reload" />
       +    <script src="/assets/application-3c2e77f06bf9a01c87fc8ca44294f3d3879d89483d83b66a13a89fc07412dd59.js" data-turbolinks-track="reload"></script>
       +  </head>
       +
       +  <body>
       +    <h1>Your Tasks</h1>
       +
       +<ul>
       +</ul>
       +
       +  </body>
       +</html>

     # ./spec/controllers/index_page_spec.rb:13:in `block (3 levels) in <top (required)>'

なんで..
天才なので閃きました
rails db:seed をしたのは開発環境、 RSpec はテスト環境に対してテストを実行している、つまり、テスト環境には seed データが投入されていない!!!!!!!!
Q.E.D.
俺でなきゃ見逃しちゃうね

..え、そうなの??
まあ、よくわかんねーけど、テスト環境でも rails db:seed してもらえばいいんじゃね?(鼻ほじ)

5.2 VS テスト環境

spec/controllers/index_page_spec.rb
before do
  `rails db:seed`
end

ダメでした

まあ流石にダメな予感はしてました。

With RSpec, how to seed the database on load?

めっちゃそれっぽい!!!!!!

spec/controllers/index_page_spec.rb
before do
  `rails db:reset RAILS_ENV=test`
end

さっきのはニアピンだったんですね。
rails コマンドは ENV=development に向けてやってる見たい
ここでしっかりと「お前はテスト向きにコマンドやりやがれ」と命令してあげる事で、はいわかりましたテスト向きですね。と聞き分けよくやってくれるみたい

それと、毎回 rails db:seed をやると無限にデータが増えるので、 rails db:reset にしました

web
  1) TasksController show index show task list on index page
     Failure/Error: expect(response.body).to eq 'task 001 : hogehoge'

       expected: "task 001 : hogehoge"
            got: "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Myapp</title>\n    \n    \n\n    <link rel=\"styleshee.../li>\n  <li>task 002 : fugafuga</li>\n  <li>task 003 : piyopiyo</li>\n</ul>\n\n  </body>\n</html>\n"

       (compared using ==)

       Diff:
       @@ -1,2 +1,23 @@
       -task 001 : hogehoge
       +<!DOCTYPE html>
       +<html>
       +  <head>
       +    <title>Myapp</title>
       +    
       +    
       +
       +    <link rel="stylesheet" media="all" href="/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css" data-turbolinks-track="reload" />
       +    <script src="/assets/application-3c2e77f06bf9a01c87fc8ca44294f3d3879d89483d83b66a13a89fc07412dd59.js" data-turbolinks-track="reload"></script>
       +  </head>
       +
       +  <body>
       +    <h1>Your Tasks</h1>
       +
       +<ul>
       +  <li>task 001 : hogehoge</li>
       +  <li>task 002 : fugafuga</li>
       +  <li>task 003 : piyopiyo</li>
       +</ul>
       +
       +  </body>
       +</html>

     # ./spec/controllers/index_page_spec.rb:17:in `block (3 levels) in <top (required)>'

おおおおおおお!!!入ってるっぽいじゃん!!!

まあただ、全然違う箇所見てるよ、と怒られてしまったので、
expect(response.body).to eq 'task 001 : hogehoge'
この辺をいじる

5.3 データの取得方法

spec/controllers/index_page_spec.rb
it 'show task list on index page' do
      get :index
      expect(response).to render_template('index')
      expect(response.body.ui.li).to include 'task 001 : hogehoge'
    end

すげー適当

web
  1) TasksController show index show task list on index page
     Failure/Error: expect(response.body.ui.li).to include 'task 001 : hogehoge'

     NoMethodError:
       undefined method `ui' for #<String:0x0000561683469d40>
     # ./spec/controllers/index_page_spec.rb:17:in `block (3 levels) in <top (required)>'

だよね。

ということは、これまでの経験的に、画面に表示されている要素を取得するため Gem が用意されているのではないだろうか?という仮説が立つ

capybaraのhave_contentなどで、含まれていてほしい単語の数を指定したい。
ほら
で、次は capybara を調べる
capybara
ほらぁ!!!!

成長を感じている...
そしてググり力も上がってきている...
にっこり。

Gemfile
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

あれれ??すでにいるんですけど...ドユコト

If the application that you are testing is a Rails app, add this line to your test helper file:
翻訳:
テストしているアプリケーションがRailsアプリケーションの場合は、この行をテストヘルパーファイルに追加します。

へ〜、入ってるだけじゃ使えないのね

spec/controllers/index_page_spec.rb
require 'rails_helper'
require 'capybara/rails'
~~

it 'show task list on index page' do
    get :index
    expect(response).to render_template('index')
    expect(page).to have_content('task 001 : hogehoge')
end

よし、これで使えるわけだ

  1) TasksController show index show task list on index page
     Failure/Error: expect(page).to have_content('task 001 : hogehoge')

     NameError:
       undefined local variable or method `page' for #<RSpec::ExampleGroups::TasksController::ShowIndex:0x0000558ab86d98e8>
     # ./spec/controllers/index_page_spec.rb:19:in `block (3 levels) in <top (required)>'

ダメみたい
そもそもpageって何よって感じに思ってたらそこで怒られた、capybaraを理解する必要がありそう

5.4 VS capybara

いや、長い。まじで

5.4.1 エラー発見しやすくしてみた
it 'show task list on index page' do
  visit '/index'
  get :index
  expect(response).to render_template('index')
  expect(page).to have_content('task 001 : hogehoge')
end

capybara が使えてんのかダメなのか、確認するために
capybara の method かな? visit を最初に書いておく
ここで落ちれば capybara がちゃんと入ってないことが証明されるだろう

1) TasksController show index show task list on index page
     Failure/Error: visit '/index'

     NoMethodError:
       undefined method `visit' for #<RSpec::ExampleGroups::TasksController::ShowIndex:0x00005564b14ad970>

ちなみにダメでした。

5.4.2 requore の記載場所を変えてみた

capybara の公式に

Load RSpec 3.5+ support by adding the following line (typically to your spec_helper.rb file):

spec_helper.rb にかけってって書いてありました
せっかくなのでrails_helper も一緒に引っ越ししましょう。

spec_helper.rb
require 'rails_helper'
require 'capybara/rails'
require 'capybara/rspec'

同じエラー

ちょっとまじできつい、わからない

やろうとしてることが難しいのかなとも思ったけど、
画面に表示されているもの取得するだけなんだから難しくないでしょうに

助けてください。

  • したいこと。
    • index ページできちんとモデルが表示されているかのテスト
    • seed データを入れて、ローカルホストに接続したら seed データが表示された
    • テストでも同じことをしたい
  • わからないこと
    • そもそも開発環境で使っている seeds をテストでも使うのが普通なのか
    • capybara を使う必要があるのか
    • 使うとしたら何が間違っていたのか
    • 使わないならどうしたらいいのか

すごくざっくりした質問になってしまって申し訳ございません。

また、質問をするなら Qiita じゃなくて、ここの方がいいよ、とかあったら教えてください。

5.4.3 敗退

やめました。
capybara 使うのやめました。

it 'show task list on index page' do
  get :index
  expect(response).to render_template('index')
  expect(response.body).to include 'task 001 : hogehoge'
end

これで通りました。
この方向でもっとちゃんと探したい。

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