Rspecでテストコード を書く② 〜テストの準備とProjectモデル編〜

TECH::CAMP卒業まであと20日となりました。
今日は、前回書いたテストコード についての記事の続きを書こうと思います。

前回テストを通したuserモデルとアソシエーションを組んでいる、projectモデルというものをテストしようと思います。

作業の前に

  • gemのインストール
group :test do
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'faker', "~> 2.8"
  gem 'rails-controller-testing'    #コントローラーのテストをする場合
end
$ rails g spec:install
  • .rspec ファイルへの追記
--format documentation
  • rails.helper.rb ファイルへの追記
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods    #ここを追記
 #省略
end

DB design

DB設計は下記の通り。アソシエーションも記載しています。

  • users table
Column Type Options
username string null: false
email string null: false, unique: true
password_digest string null: false
  • Association
    • has many projects
  • projects table
Column Type Options
name string null: false
user_id integer null: false, foreign_ley: true
  • Association
    • belongs_to user

FactoryBotの準備

アソシエーションからわかることとして、
projectはuserに依存している = userの情報がないと、projectが作られないのです。
これはテストの世界でも一緒です。
なので、「projectを保存できる」という条件でテストを通すためには、
事前にFactoryBotで、userの情報と、userの情報を入れたprojectの情報を作ってやる必要があります。

  • spec/factories/user.rb
FactoryBot.define do

  factory :user do
    password = Faker::Internet.password(min_length:8)
    username                {"username"}
    email                   {Faker::Internet.email}
    password                {password}
    password_confirmation   {password}
  end

end
  • spec/factories/project.rb
FactoryBot.define do

  factory :project do
    name          {"project"}
    user     
  end

end


projectモデルのFactoryBotに上記のように「user」と記載することで、
FactoryBotで作ったuserの情報が入るようになっています。
ただ、ユーザーの情報が入るカラムが2つあったりする場合は、この方法だとうまくいきませんでした。
その場合はprojectsモデルのFactoryBotにはuserとは書かず、
rspec

 user = create(:user)
 project = build(:project, user_id: user.id)

という風に、userを生成のうえ、そのユーザーはprojectsテーブルのどのカラムに入るのかを指定してやるとうまくいきました。



rspecを書く

では、rspecのテストコードを書いていきましょう!

require 'rails_helper'
describe Project do
  describe '#create' do
    it "nameがないと登録できないこと" do
      project = build(:project, name: nil)
      project.valid?
      expect(project.errors[:name]).to include("can't be blank")
    end

    it "nameが31文字以上だと登録できないこと" do
      project = build(:project, name: "abcdefghijklmnopqrstuvwxyzabcde")
      project.valid?
      expect(project.errors[:name]).to include("is too long (maximum is 30 characters)")
    end

    it "user_idがないと登録できないこと" do
      project = build(:project, user_id: nil)
      project.valid?
      expect(project.errors[:user]).to include("must exist")
    end

    it "name,user_id があれば登録できること" do
      expect(build(:project)).to be_valid 
    end
    
    it "nameが30文字以内であれば登録できること" do
      expect(build(:project, name: "abcdefghijklmnopqrstuvwxyzabcd")).to be_valid 
    end
  
  end

end

上記テストですが、userがないとエラーになってしまいます。
実際の環境でもuserがないとprojectsが保存できないのですから、
テストでしっかり反映されているということですね。


まとめ

前回userモデルのテストを行いましたが、
今回アソシエーションを組んでいるモデルのテストを書いたことで、
rspecの理解が深まりました!
わかってくるとテスト楽しい!

rspecに関する書籍がってあまり見つからない(電子書籍はありました!)ため、
学んだことはしっかりと書き留めて忘れた時に見直せるようにしておきたいです。