配列を持ったインスタンス変数のテストコード 【rspec】【初心者】
Twitterのindexアクションで定義されているであろう@tweetsのテストコードはどのように書いていくかを見ていきます。
tweets_controller_spec.rb
describe 'GET #index' do it "populates an array of tweets ordered by created_at DESC" do end end
(ここではindexアクションのビューの遷移のテストコードは省きます)
tweets_controller.rb
class TweetsController < ApplicationController def index @tweets = Tweet.includes(:user).order("created_at DESC") end
factory_botではダミーのインスタンスを一つしか生成していません。
create_list
そこでcreate_listメソッドを利用し、factory_botの設定ファイルに存在しているリソースを複数作成し、それを変数に代入します。
it "populates an array of tweets ordered by created_at DESC" do tweets = create_list(:tweet, 3) get :index end
create_listメソッドは第一引数に作成したいリソースをシンボル 型で、第二引数に作成したい個体数を数字で渡します。
ここで、tweetを3つ作ると、それに伴いuserも3名分作成されます。その際、同じemailで作成してしまうとUserモデルのバリデーションに引っかかりエラーが起きます。
そのため、FakerというGemで、ダミーデータを生成します。
Faker
まずは"faker", "~> 2.8"をGemに追加し、bundle installします。
そしてtweets.rbを以下のように編集してください。
tweets.rb
FactoryBot.define do factory :tweet do text {"hello!"} image {"hoge.png"} created_at { Faker::Time.between(from: DateTime.now - 2, to: DateTime.now) } user end end
ここではこのように書くんだな、という風な認識で大丈夫です。
テストコードをさらに編集していきます。
describe 'GET #index' do it "populates an array of tweets ordered by created_at DESC" do tweets = create_list(:tweet, 3) get :index expect(assigns(:tweets)).to match(tweets.sort{ |a, b| b.created_at <=> a.created_at } ) end it "renders the :index template" do end end #
matchマッチャ
引数に配列クラスのインスタンスをとり、expectの引数と比較するマッチャ です。
sortメソッド
example内で定義しているtweetsの中身の順番を、created_atを基準に降順で並び替えるメソッド。@tweetsはcreated_atで降順にソートしている(.order("created_at DESC")ため、この状態を再現する必要がある。
以上で、配列を持ったインスタンス変数のテストコードの基本は終了です。
他人に説明する感覚で、一行一行何を書いているか理解していきましょう!
expect(x).to eq y 【rspec】【完全初心者用記事】
エクスペクテーションの式の記法について悩んだことがありましたので共有します。
expect.(x).to eq y
上記のような式の場合、
x : テストコード内で生成された値
y : 実際のコントローラやモデルなどで生成される値
の認識でいましたがこれは大きな間違いだったようです。
そもそものエクスペクテーションの文法について考えてみます。
「xの部分に入れた式の値がYの部分の値と等しければ、テストが成功します」
要は、xとyが等しけりゃ(この場合はeqマッチャ なので)OK 〜ってことです。
なぜこの疑問が浮かんだかも備忘録的に残しておきます。
・x:テストの値 y:実際の値の場合(Userモデルのテストコード)
require 'rails_helper' describe User do describe '#create' do it "is invalid without a nickname" do user = build(:user) user.valid? expect(user.errors[:nickname]).to include("can't be blank") end end end
・x:実際の値 y:テストの値(Tweetsコントローラー、editアクションのテストコード)
describe 'GET #edit' do it "assigns the requested tweet to @tweet" do tweet = create(:tweet) get :edit, params: { id: tweet } expect(assigns(:tweet)).to eq tweet end it "renders the :edit template" do end end
また、コントローラのテストの
assignsメソッドは基本的にexpectメソッドの引数に使われるのでこの形をとるそう。
コントローラでインスタンス変数のテストコードを書く際はこの記法は重要なので覚えておくといいかもです。
factory_bot 【rspec】 【完全初心者用】
factory_botとは?
簡単にダミーのインスタンスを作成することができるGem。ここではspecファイルの記述を効率化するために使用します。
factory_botの導入
- Gem"factory_bot_rails"をインストールする
- specディレクトリ直下にfactoriesというディレクトリを作成する
- その中に作成したインスタンスの複数形のファイル名でRubyのファイル(ここではusers.rb 、前回の記事を参照しています。)を作成する。
- rails_helper.rb内を以下のように編集
RSpec.configure do |config| #下記の記述を追加 config.include FactoryBot::Syntax::Methods end
- users.rbを以下のように編集。このように予めUserクラスのインスタンスを定義することで、specファイルの中で特定のメソッドにより簡単にインスタンスを精製できる。(これで準備は完了です)
FactoryBot.define do factory :user do nickname {"kida"} email {"kida@gmail.com"} password {"00000000"} password_confirmation {"00000000"} end end
factory_bot の基本的なメソッド
- buildメソッド
引数にシンボル 型でとったクラス名のインスタンスを 作成する
#factory_botを利用しない場合 user = User.new(nickname: "kida", email: "kida@gmail.com", password: "00000000", password_confirmation: "00000000") #factory_botを利用する場合 user = build(:user)
- createメソッド
buildとほぼ同じ働きだが、このメソッドではテスト用のDBにデータが保存される。しかし、テストが実行され終了するたびにテスト用のDBはロールバックされるので、binding.pryなどでテストの実行を一時停止しないとテスト用のDBに保存された値をSequelProなどで確認できない
このようにfactory_botを使うことで冗長な記述が短くなり、より見やすくすることができました。
モデルのテストコード 【rspec】【完全初心者用の記事です】
モデルのテスト
モデルのテストでは、モデルで設定されたバリデーションに関するテストコードを書いていきます。
テストコードの基本
describe "hoge" do it "1 + 1は2になること" do expect(1 + 1).to eq 2 end end
- describe:テストのグループ化を宣言しています。""内にはそのまとまりの説明を書きます。
- it:itはテストをexampleと呼ばれる実際に動作するテストコードのまとまりを表します。
- エクスペクテーション:
expect(X).to eq Y
で記述し、"X が Y と等しいことを期待する"と読み解きます。ここでは "1 + 1 が 2になることを期待する" テストです。なお、これが正しければ、エクスペクテーションをパスした、テストが成功した、とされます。 - マッチャ :エクスペクテーションの中で、テストが成功する条件を示します。ここではeq(等しければ)という意味にもなります。抹茶ではありません。
実際にコードを書いていく
以下のようなUserモデルのテストコードを実際に書いていきましょう
user.rb
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable has_many :tweets has_many :comments validates :nickname, presence: true, length: { maximum: 6 } end
まずはspec/modelsディレクトリ直下にuser_spec.rbを作成します。
その中に基本となるコードを記述します。
user_spec.rb
require 'rails_helper' describe User do describe '#create' do it "is invalid without a nickname" do
user = User.new(nickname: "", email: "kkk@gmail.com", password: "00000000", password_confirmation: "00000000") user.valid? expect(user.errors[:nickname]).to include("can't be blank")
end
end
end
さぁ、一つ一つ読み解いていきましょう。
- require "rails_helper" ではrails_helper.rb内の記述を読み込み、共通の設定を有効にします。これは全てのspecファイルで必要な記述です。
- describeはネストにすることができます。ここでは、"Userクラスのテストのまとまり"の中に"Userクラスのcreateメソッドをテストするまとまり"がネストされています。
- メソッド名の前には#をつけましょう。
- データを持ったインスタンス変数にvalid?メソッドが適用されています。このメソッドはインスタンスを保存する際に「バリデーションにより保存ができない状態であるか」を確かめます。返り値にtrue,flaseを返します。
- expectの引数で、インスタンス変数にerrorsメソッドが利用されています。このメソッドは、valid?メソッドを利用したインスタンスに対して、「バリデーションにより保存ができない状態である場合なぜできないのか」を確認することができます。ここでカラム名を指定することで、そのカラムが原因のエラー文(RailsのGemで元々用意されているエラー分)が入った配列を取り出すことができます。
- マッチャ としてincludeマッチャ が使われています。これは引数にとった値が、expectの引数である配列に含まれているかをチェックするマッチャ です。ここでは("can't be blank")を引数として設定しており、実際にその通りであればエクスペクテーションはパスしたことになります。
最後にターミナルで"bundle exrec rspec"コマンドを実行し、以下のような結果になればテストは成功した、と言えます。
User #create is invalid without a nickname Finished in 0.53132 seconds (files took 3.64 seconds to load) 1 example, 0 failures
Rspecの準備 【Rails】【初心者による完全初心者用の記事です】
テストとは?
そもそもテストって何をすることで、何が目的なんでしょうか?
答えは、事前にエラーになりうる箇所を発見、修正し、用件の漏れを防ぐためです。
Rspec
RailsにおいてはRspecというRubyを基に作成されたテストに特化した言語。これを用いて、基本的にはモデルとコントローラのファイルに対してテストコードを作成していきます。
単体テストと統合テスト
テストは、
一つのプログラムのまとまりに関して、それ単体が正常に動くか確かめる単体テストと、複数のプログラムが連動して行われる処理が意図した通りに行われるか確かめる統合テストの2つがあります。
この記事では単体テストをメインに解説していきます。
Rspecの準備
- 該当のディレクトリでGem "rspec-rails"をインストール
- "rails g rspec:install"コマンドでrspec用の設定ファイルを作成
- .rspecファイルに 右記をを追加 "--format documentation"
- "bundle exrec rspec"コマンドを実行し、以下のような結果を確認する
No examples found. Finished in 0.00031 seconds (files took 0.19956 seconds to load) 0 examples, 0 failures
- 上のコマンドで生成されたspecディレクトリ以下にmodels , controllers ディレクトリを作成する(これでRspecの準備は完了です!)
テックキャンプ受講2週間経った今の備忘録。
ひとまずHTML ~Rails , github までの一通りを学びました。2週間でここまで勉強できるもんなんですね。
そんな今日は学習したアウトプットではなく、今思っていることを備忘録的にここで書かせてもらいます。
未経験エンジニアの転職情報収集してると、当たり前ですが転職活動はなかなかハードな様です。
自分は路頭に迷うのではないかとふと不安になりましたが、不安はコントロールできません。ここで深呼吸。
不安を軽減させる唯一の方法は、正しい方向に正しい姿勢でアクションを起こすこと。ここでは、テックキャンプ卒業時にまずは周りよりぶち抜けているために日々の学習量を多くする。受講生の皆さんも一生懸命されている方ばかりなので難しいとは思いますが、これをやり切ることが価値がありますよね。
筋トレもそうですけど、最後は気持ち!
書くとスッキリしました。
次回はしっかり技術のアウトプットします。笑
Git/GitHubに関して
7/1 今日は一日Git/GitHubについて学んでいました。
Githubはチラッと触っていたことがあったのですが、知らない用語がずらずらと、、。
事前学習をしていたこともあり、今まではスムーズに学習できていたのですが
今日はしっかりつまづきました。
Rails やってる方が悩むところ少ないのは、gitに対する全体像に対する理解が曖昧だからかもしれないですね。やっぱりそれは実際使っていく中でで養われるとして、、、まぁでも覚えるところは覚えないと!
ということで
Git/Githubについてまとめておこうと思います。長くなりそうです。w
Gitとは?
ソースコードをはじめとするファイルの変更履歴を記録するシステム。このシステムを使うことで、何か問題があった際に過去のファイルに戻れるようになる。
GitHubとは?
Gitの仕組みを利用したWebサービスのこと。Gitの機能に対してさらに、チーム開発に便利な機能を付け加え、リモートリポジトリとしての役割も果たす。
リポジトリとは?
変更履歴を管理しておくための入れ物。ローカルリポジトリ、リモートリポジトリがある。ローカルリポジトリは自分のPC上におくリポジトリであるのに対して、リモートリポジトリは外部のサーバーなどにおくリポジトリをさす。
クローンとは?
リモートリポジトリを複製して、ローカルリポジトリを作成すること。
インデックスとは?
コミットするファイルを一時的に登録する場所。
一度に多くのファイルを変更した際に、どのファイル単位でコミットするかを選択できるようにするため。
コミットとは?
ディレクトリやファイルの状態を記録するための操作。コミットすることで現在の状態が、日時や変更を加えた人の情報も含めて一緒に保存できる。
1機能1コミットのようになるべく細かく行うのがベター。
プッシュとは?
ローカルリポジトリで加えた変更をリモートリポジトリに同期させること。
ブランチとは?
リポジトリで管理しているプロジェクトの履歴の一つ。これを使うことで、開発者ごとに機能を明確に分けることができ、完成途中や問題のあるソースコードをリリースしなくて済む。
プルとは?
リモートリポジトリの変更履歴をローカルリポジトリに反映させる操作のこと。
プルリクエストとは?
作成したブランチをmasterブランチ(大元のブランチ)にマージするときの確認作業のこと。掲示板のようなもので、ここで他の開発者からの確認・レビューが行うことができる。
マージとは?
ブランチとブランチを結合させること。
デプロイとは?
コンフリクトとは?
複数の人が別のブランチで同じ箇所を編集してしまい、変更箇所を自動では判断できずにマージできなくなること。
コンフリクト解決のフローは?
1:コンフリクト箇所を現在の変更があるブランチに反映
2:コンフリクト箇所を修正
3:コンフリクト解決をコミット
4:現在の変更があるブランチをマージ
git revert とは?
コミットを打ち消すコミットを生成するコマンド。