如何在Rails控制器测试中断言响应代码?

时间:2011-11-16 22:13:10

标签: ruby-on-rails ruby-on-rails-3

修改 编辑改为关于测试而不是代码的问题,因为我看到应用程序行为正确。

我正在编写一个Rails 3应用程序,它纯粹是一个RESTful Web服务(即没有视图)。我有一个用户模型,用户名是unqiue

class User < ActiveRecord::Base
    validates_uniqueness_of :username
end

在我的控制器中,我有以下代码来处理正在创建的新用户:

def create
  @user = User.new(ActiveSupport::JSON.decode(request.raw_post))
  if @user.save
    puts "Added user #{@user.username}"
    format.json { render :json => "" }
  else
    puts "Failed to add user: #{@user.errors.to_json}"
    render json: @user.errors, status: :unprocessable_entity
  end
end

然后我进行了一项功能测试,创建了一个与现有用户具有相同用户名的用户:

test "should not create user with duplicate username" do
  @jim = users(:jim)
  post '/users', @jim.to_json, "CONTENT_TYPE" => "application/json"
  assert_response :unprocessable_entity
end

当我运行测试时,控制器输出“无法添加用户:{”用户名“:[”已被采用“]}”按预期方式,但测试失败: 预期的响应是&lt;:unprocessable_entity&gt;,但是&lt; 200&gt;

然而,随着卷曲,我得到了我期望的回应:

curl -i -X POST -d '{"username": "james", "email": "test@test.com" }'
HTTP/1.1 422
{"username":["has already been taken"]}

那么我在测试中的断言在哪里出错?

2 个答案:

答案 0 :(得分:0)

您可能应该使用respond_with。它将处理许多REST逻辑,包括设置状态代码。

此外,对于只是REST服务的应用程序,Rails可能过度。您可能想要考虑Sinatra。

答案 1 :(得分:0)

原因是我转而使用RackTest来允许我在正文中发布JSON(即不作为表单参数。)因此,我应该在last_response上做出断言(RackTest MockResponse用于后调用)而不是使用assert_response:

  test "should not create user with duplicate username" do
    @jim = users(:jim)
    post '/users.json', @jim.to_json, "CONTENT_TYPE" => "application/json"
    assert_status :unprocessable_entity
  end

  def assert_status(expected_status)
    assert_equal last_response.status, Rack::Utils.status_code(expected_status)
  end

我很惊讶assert_response:当没有调用任何方法为@response产生值时成功通过。如果该断言失败,或者抛出异常,那么追踪我的错误就更容易了,但是请大家好看!