[ruby on rails]rails中rspec实战

一.安装

group :development, :test do
  gem 'rspec-rails'
  gem 'factory_bot_rails'  # 批量生成假资料
  gem 'rails-controller-testing' # 测试controller
  gem 'shoulda-matchers' # 测试validates
  gem 'faker'  # 造假数据用的
end
rails generate rspec:install
  • gem 'rails-controller-testing' 可以添加 type: :controller , 可以使用get :index
RSpec.describe CoursesController, type: :controller do
  describe 'GET /index' do
    it 'render template' do
      get :index
      expect(response).to render_template(:index)
    end
  end
end

## 同上面
RSpec.describe 'Courses', type: :request do
  describe 'GET /index' do
    it 'render template' do
      get '/courses'
      expect(response).to render_template('courses/index')
    end
  end
end

二、 配置

1. 基础配置文件spec_helper.rb

# spec_helper.rb
config.default_formatter = "doc"

2.配置factory_bot github地址

  • 生成配置文件
mkdir spec/support
touch spec/support/factory_bot.rb
  • 编辑factory_bot.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
  • 编辑rails_helper.rb,加上下面这句,里边默认有,可以直接打开注释
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
  • FactoryBot的档案惯例是放在spec/factories.rb
touch spec/factories.rb
  • 自定义Post Factory
FactoryBot.define do
  factory :post do
    title { "first post" }
    is_publish { false }
    # 传参 就可以使用 create(:post, alipay_account: create(:alipay_account))
    transient do
      bankcard { nil }
      alipay_account { nil }
    end
    
    before(:create) do |[post, evaluator|
      card = evaluator.bankcard # 上面 transient里定义的, 通过 create(:post, bankcard: create(:bankcard))传过来的
      if card
        post.extra = card.basic_info_in_json
        post.user = card.owner
      end
      account = evaluator.alipay_account
      if account
        post.extra = account.basic_info_in_json
        post.user = account.user
      end
    end
  end
  
  factory :course do
    title { 'Title' }
    trait :title_a do
      title { 'A' }
    end
    trait :title_b do
      title { 'B' }
    end
  end
end
  • 建立一个post,只要build(:post) 或者 create(:post)
#rails_helper.rb里加了Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }才可以这样用
create(:post)  
create(:course, :title_a)  # => #<Course id: 1, title: "A" >
create(:course)  # => #<Course id: 1, title: "Title" >
#相当于
FactoryBot.create(:post)

3.配置shoulda-matchers github地址

  • 生成配置文件
touch spec/support/shoulda_matchers.rb
  • 编辑shoulda_matchers.rb
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
  • 测试validates 在 spec/models/course_spec.rb
RSpec.describe Course, type: :model do
  it { is_expected.to validate_presence_of(:title) }
  it { is_expected.to belong_to(:user) }
end

三. 使用

1. 测试controller

# spec/requests/courses_spec.rb
require 'rails_helper'

RSpec.describe 'Courses', type: :request do
  describe 'GET /index' do
    it 'assigns @courses' do
      course1 = create(:course)
      course2 = create(:course)
      get '/courses'
      expect(assigns[:courses]).to eq([course1, course2])
    end

    it 'render template' do
      get '/courses'
      expect(response).to render_template('courses/index')
    end
  end

  describe 'GET /show' do
    let(:course) { create(:course) }
    it 'assign @course' do
      get "/courses/#{course.id}"
      expect(assigns[:course]).to eq(course)
    end

    it 'render show template' do
      get "/courses/#{course.id}"
      expect(response).to render_template('courses/show')
    end
  end

  describe 'GET /new' do
    it 'assign @course' do
      get '/courses/new'
      expect(assigns(:course)).to be_a_new(Course)
    end

    it 'render template' do
      get '/courses/new'
      expect(response).to render_template('courses/new')
    end
  end

  describe 'POST /create' do
    let(:course) { build(:course) }
    context 'when course have title' do
      it 'create a new record' do
        expect do
          post '/courses', params: { title: course.title, description: course.description }
        end.to change { Course.count }.by(1)
      end

      it 'redirect to index page' do
        post '/courses', params: { title: course.title, description: course.description }
        expect(response).to redirect_to courses_path
      end
    end

    context "when course doesn't have tile" do
      it 'create a new record' do
        expect do
          post '/courses', params: { description: course.description }
        end.to change { Course.count }.by(0)
      end

      it 'redirect to index page' do
        post '/courses', params: { description: course.description }
        expect(response).to render_template 'courses/new'
      end
    end
  end

  describe 'GET /edit' do
    it 'assign @course' do
      course = create(:course)
      get "/courses/#{course.id}/edit"
      expect(assigns[:course]).to eq(course)
    end

    it 'render edit template' do
      course = create(:course)
      get "/courses/#{course.id}/edit"
      expect(response).to render_template('courses/edit')
    end
  end

  describe 'PUT /course/:id' do
    let!(:course) { create(:course) }
    context 'when the course has title' do
      it 'assign @course' do
        put "/courses/#{course.id}", params: { course: { title: course.title } }
        expect(assigns[:course]).to eq(course)
      end

      it 'change value' do
        put "/courses/#{course.id}", params: { course: { title: 'course.title'} }
        expect(assigns[:course].title).to eq('course.title')
      end

      it 'redirect to show page' do
        put "/courses/#{course.id}", params: { course: { title: 'course.title'} }
        expect(response).to redirect_to course_path(course)
      end
    end

    context "when the course dosen't has title" do
      it 'doesn\'t change value' do
        put "/courses/#{course.id}", params: { course: {  title: "" }  }
        course.reload  # 注意reload 取更新后的course
        expect(assigns[:course].title).not_to eq(course.title)
      end

      it 'render edit page' do
        put "/courses/#{course.id}", params: { course: { title: '' } }
        expect(response).to render_template 'courses/edit'
      end
    end
  end

  describe 'DELETE /course/:id' do
    let!(:course) { create(:course) }
    it 'deletes a course' do
      expect do
        delete "/courses/#{course.id}"
      end.to change { Course.count }.by(-1)
    end

    it 'redirect to index page' do
      delete "/courses/#{course.id}"
      expect(response).to redirect_to courses_path
    end
  end
end

2. 测试route

# spec/routing/homepage_spec.rb
require "rails_helper"

RSpec.describe "Homepage" do
  it "route root path to course # index" do
    expect(get: "/").to route_to(controller: "courses", action: "index")
  end
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值