Skip to main content
The Kai Way

[译文] Shoulda教程4 - Test Controller

基本的控制助手方法

如ActiveRecord宏一样,Shoulda 提供了一套测试控制器的宏,以尽可能简洁的方法进行测试。所有的这些方法都在Shoulda的Rdoc中,但这里再送上一个快捷的例子:

    class UsersControllerTest < Test::Unit::TestCase
        context "on GET to :show" do
            setup { get :show, :id => 1 }

            should_assign_to :user
            should_respond_with :success
            should_render_template :show
            should_not_set_the_flash

            should "do something else really cool" do
                assert_equal 1, assigns(:user).id
            end
        end

        context "on POST to :create" do
            setup { post :create, :user => {:name => 'Ronald', :party => 'Repukeulan' } }
            should_assign_to :user
            should_redirect_to "user_url(@user)"
            should_set_the_flash_to(/created/i)
        end
    end

应该RESTful #

这里每个 should_xxx 宏都会产生一个单独的测试方法,编写起来又DRY。而should_be_restful 宏可以产生遵循基本的RESTful设计模式的控制器。should_be_restful 宏就像一个超级测试生成器,每次调用是都会产生40到50个测试方法。这里有个超简单的例子:

    class UsersControllerTest < Test::Unit::TestCase
        def setup
            @user = User.find(:first)
        end

        should_be_restful do |resource|
            resource.create.params = { :name => "Billy Bumbler", :party => 'Sure do!'}
            resource.update.params = { :name => "Changed" }
        end
    end

这里会生成一整套包含全部CRUD行为的测试,也包括 :new 和 :edit 。对这个宏还有很多定义的空间,能让它处理各种情况的控制器,不过默认设置已经非常智能了。在上面的例子中,通过测试类名就能查找出如何处理User模型,users_url方法,params[:user],@user 和@users实例变量等。

配置should_be_restful #

来看看更改should-be_restful产生的测试的行为的方法。(这些也在Rdoc文档中有详细记录)

      class UsersControllerTest < Test::Unit::TestCase
          def setup
              @user = User.find(:first)
          end

          should_be_restful do |resource|
              resource.klass      = User
              resource.object     = :user
              resource.parent     = []
              resource.actions    = [:index, :show, :new, :edit, :update, :create, :destroy]
              resource.formats    = [:html, :xml]

              resource.create.params = { :name => "bob", :email => '[email protected]', :age => 13}
              resource.update.params = { :name => "sue" }

              resource.create.redirect  = "user_url(@user)"
              resource.update.redirect  = "user_url(@user)"
              resource.destroy.redirect = "users_url"

              resource.create.flash  = /created/i
              resource.update.flash  = /updated/i
              resource.destroy.flash = /removed/i
          end
      end

下面是参数的具体解释:

在#create,#update和#destory测试中可以附上一些参数:

Denied行为 #

RESTful控制器的部分或全部的行为在大多数场景里是有访问限制的(比如需要用户认证的时候)。resource.denied选项让should_be_restful原生地支持行为的访问限制。

    class UsersControllerTest < Test::Unit::TestCase
        def setup
        @user = User.find(:first)
        end

        should_be_restful do |resource|
            resource.create.params = { :name => "bob", :email => '[email protected]', :age => 13}
            resource.update.params = { :name => "sue" }

            resource.denied.actions  = [:new, :create, :edit, :update, :destroy]
            resource.denied.redirect = "new_session_url"
            resource.denied.flash    = /administrator/i
        end
    end

每个列在resource.denied.actions的行为(默认为空)将测试行为被限制访问,相关的记录不会被触及。 :redirect 和 :flash 参数和上面的 resource.create 和 resource.update 一样。

混合使用should_be_restful和上下文 #

测试每个控制器和所有控制器行为时,混合should_be_restful和上下文代码块是一个非常强大的方法。下面的代码是在我们(作者)的应用的测试中很常见到。

    class PostsControllerTest < Test::Unit::TestCase
        def setup
            @user = users(:bob)
            @post = @user.posts.first
        end

        context "An administrator" do
            setup { login_as users(:admin) }

            should_be_restful do |resource|
                resource.create.params = { :subject => "test", :body => "message" }
                resource.update.params = { :subject => "changed" }
            end
        end

        context "A user" do
            setup { login_as @user }

            should_be_restful do |resource|
                resource.create.params = { :subject => "test", :body => "message" }
                resource.update.params = { :subject => "changed" }
            end
        end

        context "A stranger" do
            setup { login_as users(:sally) }

            should_be_restful do |resource|
                resource.create.params   = { :subject => "test", :body => "message" }
                resource.denied.actions  = [:edit, :update, :destroy]
                resource.denied.redirect = "login_url"
                resource.denied.flash    = /only the owner can/i
            end
        end

        context "The public" do
            setup { logout }

            should_be_restful do |resource|
                resource.denied.actions  = [:new, :create, :edit, :update, :destroy]
                resource.denied.redirect = "signup_url"
                resource.denied.flash    = /must be a member/i
            end
        end
    end

混合与匹配 #

最后,记住更好的测试在should_be_restful助手之外的额外行为,或者在Shoulda中加入一般的test_xxx方法。

    class UsersControllerTest < Test::Unit::TestCase
        def setup
            @user = User.find
        end

        should_be_restful do |resource|
            resource.create.params = { :name => "Billy Bumbler", :party => 'Sure do!'}
            resource.update.params = { :name => "Changed" }
        end

        context "on GET to /users/:id;activate"
            setup { get :activate, :id => @user.id }
            should_render_template :activate
            # etc.
        end

        def test_normal_stuff
            assert true
        end
    end