【发布时间】:2014-02-09 11:03:03
【问题描述】:
我正在构建一个非常小的 Sinatra API,今天我开始为它编写测试。我正在使用 RSpec 和 FactoryGirl。
我有一个用户模型,在控制器中我检查正在注册的用户的电子邮件是否已经保存。如果保存,则返回 402,否则创建用户并返回 200。为了对此进行测试,我使用相同的参数两次对 users 路由进行 POST,第一次检查 last_response.should be_ok因为数据库是空的,所以我可以创建用户,然后我有另一个测试,POST 到users 路由与之前的参数相同,但期待last_response.should_not be_ok,我得到了 200!所以测试失败了!!
这是我的 Sinatra 路线:
post '/users' do
user = User.where(email: params[:email]).first
if !user
user = User.create(email: params[:username], password_not_hashed: params[:password])
halt 200, {user:user}.to_json
end
halt 409, {error:"user already exists"}.to_json
end
这是我的测试:
describe 'Create User' do
include Rack::Test::Methods
params = {}
params['password'] = "username"
params['username'] = "username@username.com"
it "should create a user" do
post '/users', params
last_response.should be_ok
end
it "should fail to create a user because its duplicate user" do
post '/users', params
last_response.should_not be_ok
end
end
我失败了,因为最后一次测试的响应是 200。我用pp 打印了params 和last_response,这就是我得到的:
参数:
{"password"=>"username", "username"=>"username@username.com"}
last_response
@block=nil,
@body=["{\"user\":{\"id\":null,\"email\":\"username@username.com\"}}"],
@body_string=nil,
@chunked=false,
@errors="",
@header=
{"Content-Type"=>"text/html;charset=utf-8",
"Content-Length"=>"52",
"X-XSS-Protection"=>"1; mode=block",
"X-Content-Type-Options"=>"nosniff",
"X-Frame-Options"=>"SAMEORIGIN"},
@length=52,
@original_headers=
{"Content-Type"=>"text/html;charset=utf-8",
"Content-Length"=>"52",
"X-XSS-Protection"=>"1; mode=block",
"X-Content-Type-Options"=>"nosniff",
"X-Frame-Options"=>"SAMEORIGIN"},
@status=200,
有什么想法吗?!?!快把我逼疯了!
编辑:
刚刚添加了一个活动记录验证 (validates_uniqueness_of :email),在我的测试输出中我得到以下信息:
Failure/Error: post '/users', params
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
所以,这意味着该电子邮件已经创建了一个用户,所以我仍然不明白为什么测试失败,并且创建用户的路由总是在 if !user 内
这是代码覆盖率的输出:
疯了……我迷路了!
编辑:
我还有一个 after all rspec 钩子,但这不应该是重要的,因为它只在所有测试之后运行:
after :all do
ActiveRecord::Base.subclasses.each(&:delete_all)
end
【问题讨论】:
-
如何在第 14 行更改条件?我一直在使用 irb 中的 !user 条件,我想知道它是否始终如一地评估我们所期望的方式。我仍然不确定。使用“if user.nil”怎么样?反而?这似乎更精确一些。
-
同样的问题...改成user.nil?而且还在进去!
-
添加打印语句或断点时发生了什么?您是否能够在测试执行期间检查数据库的状态?
-
我在控制器中添加了一些打印来检查“用户”是否为 nil 并且它是 nil。也许与sqlite有关? (我在测试环境中使用的数据库......我不知道还能尝试什么,已经花了太多我们的希望有人意识到发生了什么......我想知道!!哈哈
-
根据设计,您的测试数据库不应在测试之间保留数据。如果是这样,您最终可能会在测试中遇到各种奇怪的隐藏数据依赖关系。您可以使用 rake db:prepare 任务按下测试数据库来填充您的测试数据库、调用工厂、在您的规范中创建一个 before 语句,或者在您再次调用 API 之前执行一些像我下面的建议那样的俗气来创建用户。因此,您的测试似乎工作正常,因为您没有在测试执行之前准备好您的数据库。我想知道您是如何使活动记录验证工作的。 . .