今天继续我们的功能测试实战。
项目还是:blog,大家可以从github或者gitcafe中获取项目源码。
先来介绍一个断言
assert_difference(expression, difference = 1, message = nil, &block)
http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html中比较详细的介绍。
再一次强烈推荐http://api.rubyonrails.org/,还有http://ruby-doc.org/,还有http://apidock.com/,还有http://guides.rubyonrails.org/。这四个工具网站,真是好啊,谁用谁知道。 |
assert_difference的英文解释是
Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.
直译的话就是
测试两个数值的区别。
哪两个数值呢,就是expression的数值。怎么变成一个了?不要着急,一个是block执行之前,一个是block执行之后。
意译一下就是
比较expression的数值在block执行前后的差,看这个差是否是difference 参数指定的值,这个参数是个可选参数,默认值是1。
也可以理解为,block执行之后的expression值 - block执行之前的expression值,看这个差值是否等于difference 指定的值,默认差值为1。
我们先来个简单例子说明一下。
就拿项目中的添加post来举例,对应的controller的代码如下:
- def create
- @category = Category.find(params[:post][:category_id])
- params[:post].delete(:category_id)
- @post = @category.posts.build(params[:post])
- @post.user = current_user
- @post.tag_ids = params[:tag_ids]
- if @post.save!
- flash[:notice] = "post was created successfully"
- redirect_to admin_posts_path
- else
- flash.now[:notice] = "create post failed"
- render :new
- end
- end
添加成功之后会跳转到posts列表,失败的话,就保留在new这个页面。
当然了,测试添加可以有很多方法。比如说添加之后,查询一下,看看是否存在。如果有标题唯一之类的验证,也可以再次添加相同的post,然后看看是否会提示已经存在。或者验证添加之后是否跳转到posts列表,是否输出正确添加的flash信息。
今天我们就是为了讲解assert_difference这个断言,前面说过了,这个断言用来判断block前后的expression的差。再添加一篇post之后,post的个数会增加一,我们就用这个断言来验证添加是否成功。
在test/functional/admin/posts_controller_test.rb文件中敲入下面的代码。
- require 'test_helper'
- class Admin::PostsControllerTest < ActionController::TestCase
- include FactoryGirl::Syntax::Methods
- def test_should_create_post_successfully
- user = FactoryGirl.create(:user_valid)
- category = FactoryGirl.create(:category_valid)
- article = FactoryGirl.build(:post_valid)
- tag = FactoryGirl.build(:tag_valid)
- assert_difference('Post.count') do
- post :create, {:post=>{:category_id=>category.id,
- :title=>article.title,
- :slug=>article.slug,
- :summary=>article.summary,
- :content=>article.content},
- :tag_ids => [tag.id]},
- {:user_id => user.id}
- end
- assert_redirected_to admin_posts_path(assigns(:posts))
- end
- end
在代码中我们使用了factory-girl模拟的数据。然后用功能测试提供的post方法想postscontroller的create方法提交了数据,因为我们添加post的过程需要用到当前用户的信息,当前用户的信息又是从session中获取的,所以在post方法中需要给session参数指定信息,使得session[:user_id]有值。
当然了,还有一种办法可以指定session的值。那就是通过@request这个变量,前面介绍functional test的时候讲过,我们有三个变量可以在功能测试中使用。
- @controller
- @request
- @response
@response.session[:user_id]=user.id也可以实现设置session的作用,这样的话,就可以省略掉post方法中的session参数部分。
变成下面的样子。
- def test_should_create_post_successfully
- user = FactoryGirl.create(:user_valid)
- category = FactoryGirl.create(:category_valid)
- @request.session[:user_id] = user.id
- article = FactoryGirl.build(:post_valid)
- tag = FactoryGirl.build(:tag_valid)
- assert_difference('Post.count') do
- post :create, {:post=>{:category_id=>category.id,
- :title=>article.title,
- :slug=>article.slug,
- :summary=>article.summary,
- :content=>article.content},
- :tag_ids => [tag.id]}
- end
- assert_redirected_to admin_posts_path(assigns(:posts))
- end
具体哪个好,这个需要大家在使用的过程中慢慢揣摩吧。其实都不错,我觉得在不同的场景,使用不同的方式。
这个测试有两个断言,一个就是assert_difference,一个是assert_redirected_to。断言是否跳转的posts列表,并且传递了posts变量。
在功能测试中可以访问的四个hash分别是:
- flash["gordon"] flash[:gordon]
- session["shmession"] session[:shmession]
- cookies["are_good_for_u"] cookies[:are_good_for_u]
- # Because you can't use assigns[:something] for historical reasons:
- assigns["something"] assigns(:something)
在下面这个场景,我觉得使用@request.session来设置session,就要比写在post的参数中好。
- require 'test_helper'
- class Admin::CategoriesControllerTest < ActionController::TestCase
- include FactoryGirl::Syntax::Methods
- def test_should_create_category_successfully
- user = FactoryGirl.create(:user_valid)
- @request.session[:user_id] = user.id
- category1 = build(:category_valid)
- category1.title = FactoryGirl.generate(:category_title)
- category2 = build(:category_valid)
- category2.title = FactoryGirl.generate(:category_title)
- assert_difference "Category.count", 2 do
- post :create, {:category => {:title => category1.title}}
- post :create, {:category => {:title => category2.title}}
- end
- end
- end
好处就是只需要设置一次,如果是写在参数中,那么就需要写两次相同的代码,维护与修改就集中了。
其实还可以用它来测试delete方法,还是测试差值,删除前后的差值,只是这个值是否是-1。
和assert_difference对应的还有一个no_difference。
assert_no_difference(expression, message = nil, &block)
用来测试block前后,expression的数值是否没有发生变化。
比如说测试一下,当post的属性中有违反validates的,这时候添加肯定会失败,block前后的Post.count应该是没有变化的。
下面就是测试添加tag失败的例子,tag的title长度要大于3,空的title自然就是无效的tag。
- def test_should_create_tag_fail
- user = create(:user_valid)
- @request.session[:user_id] = user.id
- assert_no_difference "Tag.count" do
- post :create, {:tag => { :title => ""}}
- end
- end
本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/1078404,如需转载请自行联系原作者