Rails测试:Rspec

One: Case Study

Debug sucks, and test rocks! If you use rails, then you should know how to use RSpec to test your rails app.

I use a simple case to practice basic RSpec. If you want practice, go to check the saasbook/bdd-tdd-cycle practice at the end of this articel. Here is the case. <pre>User name:string and email:string name and email should not be nil. </pre> I will test the validation of model and basic controller actions. Some revelent good resources are list at the end of this post.

Two: Set Up

Gem

We will use the most popular gems combo here.

group :development, :test do
  gem 'rspec-rails' 
  gem 'factory_girl_rails' #give us some test data to play with
end
group :test do
  gem 'capybara' #simulate users’ actions
  #detects changes and run test automatically, time saver!
  #if you use mac, make sure `gem install rb-fsevent`
  gem 'guard-rspec'
  gem 'launchy' # open browser to help you debug
end

Generate

Then run bundle install to install these gems and run rails generate rspec:install to generate necessary files. Also, if you use capybara, make sure require "capybara/rspec" is included in your spec/spec_helper.rb file.

Configration

Usually, I don't want the auto generated test file, so I would add these config to the config/application.rb file:

config.generators do |g|
    g.controller_specs false
    g.view_specs false
    g.helper_specs false
    g.routing_specs false
    g.request_specs false
end

Three: Factory Girl

It would be good if we have some data that is isolated from database to play with. And Factory Girl is a great tool to deal with this problem.

Here we want two users, one is valid and another is not. Create a new file named users.rb inside spec/factories/users.rb. And:

FactoryGirl.define do
    factory :user do |f|
        f.name "John Smith"
        f.email "hey@gmail.com"
    end

    factory :invalid_user, parent: :user do |f|
        # inherits from user
        f.name nil
    end
end

Four: Model

Now we can test our model easily. In this article, I just want to test validation of this simple User model. User with name and email are valid, invalid without name or email.

Create a new file called user_spec.rb(make sure '_spec' is included to be detected by RSpec).

require 'rails_helper'
RSpec.describe UserModel, type: :model do
    describe User do
        it "has valid user" do
            # use create, just FactoryGirl(:user) is deprecated now
            expect(FactoryGirl.create(:user)).to be_valid
        end
        
        it "is invalid without a name" do
            # use build to skip validation, it will not call 'save' method
            # when use create, our test will always fail
            expect(FactoryGirl.bulid(:user, name: nil)).to_not be_valid
        end
        
        it "is invalid without email" do
            expect(FactoryGirl.bulid(:user, email: nil)).to_not be_valid
        end
    end
end

Now I think the minmum model test is done. Model is the most inportant part of rails app, make sure they are test with high coverge. You can use simplecov to generate report. Now let's move on to controller test!

Five: Controller

In this short article, I will just test create, update and destroy, and skip index etc.

Create

describe "POST #create" do
    context "with valid attributes" do
        it "create a new user" do
            expect{
                post :create, user: FactoryGirl.attributes_for(:user)
            }.to change(User, :count).by(1)
        end

        it "redirect to new user" do
            post :create, user: FactoryGirl.attributes_for(:user)
            expect(response).to redirect_to(User.last)
            expect(flash[:notice]).to include('successfully')  
        end
    end

    context "with invalid attributes" do
        it "create a new user" do
            expect{
                post :create, user: FactoryGirl.attributes_for(:invalid_user)
            }.to_not change(User, :count)
        end

        it "render new template" do
            post :create, user: FactoryGirl.attributes_for(:invalid_user)
            expect(response).to render_template :new
        end
    end
end

Something to notice: user expect() instead should; organise your test with context if there are too many examples.

Delete

describe 'DELETE destroy' do
  before(:each) do
    # make our test DRY  
    @user = FactoryGirl.create(:user)
  end
  
  it "deletes the user" do
    # note syntax, http method and rails action
    expect{
      delete :destroy, id: @user        
    }.to change(User,:count).by(-1)
  end
    
  it "redirects to users#index" do
    delete :destroy, id: @user
    expect(response).to redirect_to users_url
  end
end

Update

describe 'PUT update' do
  before :each do
    @user = FactoryGirl.create(:user, name: "John", email: "hey@gmail.com")
  end
  
  context "valid update" do
    it "change user attributes" do
      put :update, id: @user, user: FactoryGirl.attributes_for(:user, name: "John", email: "hello@gmail.com")
      @user.reload
      expect(@user.name).to eq("John")
      expect(@user.email).to eq("hello@gmail.com")
    end
  
    it "redirects to the updated user" do
      put :update, id: @user, user: Factory.attributes_for(:user)
      expect(response).to redirect_to @user
    end
  end
  
  context "invalid update" do   
    it "does not update user's attributes" do
      put :update, id: @user, user: FactoryGirl.attributes_for(:user, name: "Michael", email: nil)
      @user.reload
      expect(@user.name).to_not eq("Michael")
      expect(@user.email).to eq("hey@gmail.com")
    end
    
    it "renders the edit view" do
      put :update, id: @user, user: FactoryGirl.attributes_for(:invalid_user)
      expect(response).to render_template :edit
    end
  end
end

Resources

Documentation How I learned to test my Rails applications Railscasts RSpec-Rails saasbook/bdd-tdd-cycle

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏VRPinea

VR运动模拟器Feel Three登陆Kickstarter,5小时完成众筹目标

美国东部时间本月28日,VR运动模拟器Feel Three登陆Kickstarter开启众筹,并于5小时内完成众筹目标。

932
来自专栏前端说吧

HTML案例—很讨巧的一种js+css制作hover模式展示二级菜单方法

3416
来自专栏大数据文摘

从如何跳橡皮筋,到如何优雅地kiss,老铁们到底在谷歌什么?

1332
来自专栏知晓程序

他构想了一个族谱小程序,就等程序员来实现了!

本文讲述的是一款解决人们想熟悉亲戚及亲戚之间关系需求的小程序,其主要的使用场景会围绕着微信的亲戚家族群组。

692
来自专栏知晓程序

再不看就没了!这个小程序,带你去武大看「校花」

这时,江城正沉浸在一片樱海之中。武汉大学校园内两千多株樱花齐齐盛开,粉白的花瓣堆积着,像浮在半空的云海。

531
来自专栏VRPinea

VR版《恋与制作人》,满足你的所有小幻想

2706
来自专栏新智元

2016年 CES 大展 VR/AR 论坛前瞻

国外 VR 媒体uploadvr最近收集整理了即将举行的 16年CES 大展上,VR/AR 部分的论坛安排。我们一起来看看。本文分两部分,按日期,上部分是 1月...

3598
来自专栏老九学堂

程序员的这些脑洞设计,正常人绝对想不到

873
来自专栏知晓程序

画风清奇!这 4 个脑洞超大的小程序,让我笑得停不下来

上线十个月以来,好玩的小程序层出不穷。什么组队敲木鱼、读口令领红包、凭颜值领红包等等等等。

702
来自专栏软件技术

程序员自创吵架神器,再也不怕没发挥好

  情侣间日常因为琐事争吵,可以说是最寻常不过的“甜蜜烦恼"。拌嘴到了最后,很多时候,以男主角道歉划上句点。

17011

扫码关注云+社区