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 条评论
登录 后参与评论

相关文章

来自专栏施炯的IoT开发专栏

转贴-30个最酷的Windows Phone 7教程

下文转自CSDN:30个最酷的Windows Phone 7教程。为以后的学习Mark一下。 导读:近期微软MSDN博客作者Ghassan Chahine列举了...

17610
来自专栏领域驱动设计DDD实战进阶

DDD实战进阶第一波(七):开发一般业务的大健康行业直销系统(实现产品上下文接口与测试)

924
来自专栏葡萄城控件技术团队

自学MVC看这里——全网最全ASP.NET MVC 教程汇总

MVC架构已深得人心,微软也不甘落后,推出了Asp.net MVC。小编特意整理博客园乃至整个网络最具价值的MVC技术原创文章,为想要学习ASP.NET MVC...

7137
来自专栏.NET开发者社区

(码友推荐)2018-10-19 .NET及相关开发资讯速递

3.Using an OData Client with an ASP.NET Core API

653
来自专栏张善友的专栏

每周.NET前沿技术文章摘要(2017-06-21)

汇总国外.NET社区相关文章,覆盖.NET ,ASP.NET等内容: .NET .NET Core Magic: Develop on one OS, run ...

1837
来自专栏智能计算时代

Instant Messaging at LinkedIn: Scaling to 10000 of Connections

We recently introduced Instant Messaging on LinkedIn, complete with typing indic...

2675
来自专栏小樱的经验随笔

2017 Multi-University Training Contest - Team 9 1001&&HDU 6161 Big binary tree【树形dp+hash】

Big binary tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65...

2716
来自专栏jessetalks

极简版ASP.NET Core学习路径及教程

绝承认这是一个七天速成教程,即使有这个效果,我也不愿意接受这个名字。嗯。 视频系列已出: http://www.cnblogs.com/jesse2013/p/...

3377
来自专栏逸鹏说道

ASP.NET Core 性能对比评测(ASP.NET,Python,Java,NodeJS)

前言 性能是我们日常生活中经常接触到的一个词语,更好的性能意味着能给我们带来更好的用户体检。比如我们在购买手机、显卡、CPU等的时候,可能会更加的关注于这样指标...

4466
来自专栏张善友的专栏

ASP.NET MVC Release Candidate 1学习指南

现在 ASP.NET MVC Release Candidate 已经可以下载, 如何着手开始用asp.net mvc开发应用呢? 这是一个学习ASP.NET ...

1749

扫码关注云+社区