我在M. Hartl的Rails教程6.3.4节末尾的用户模型的RSpec测试中遇到了问题。我完全失去了请帮助。
所有测试都与我需要帮助的测试分开:
我的问题:为什么rspec会从类似的控制台操作中得到不同的结果?如何解决这个问题并通过测试?
故障:
1)用户有效密码的验证方法的返回值
失败/错误:它{should == found_user.authenticate(@ user.password) } 预期:用户ID:1,名称:“示例用户”,电子邮件:“user@example.com”,created_at:“2013-08-21 21:38:32”,updated_at: “2013-08-21 21:38:32”,password_digest: “$ 2A $ 04 $ tjcti4yEYFuJbbz9sa.Z9.F / KXJtHU3A8onU1Fhovn3x ......” > 得到:#User id:nil,name:“Example User”,email:“user@example.com”,created_at:nil,updated_at:nil,password_digest: “$ 2A $ 04 $ 6fdtfzgCFYetjShfYKuFIObWo4Uru4xRMkhW7Ow92O.2 ...” >
完成0.64049秒20例,1次失败
失败的例子:
rspec ./spec/models/user_spec.rb:100#用户返回值 验证有效密码的方法
当我在rails控制台中手动测试时,authenticate方法返回完全相同的用户,并且所有字段都匹配。以下是我的控制台实验:
在沙箱中加载开发环境(Rails 4.0.0)Any 您所做的修改将在退出irb(主):001:0>
上回滚user = User.new(名称:“示例用户”,电子邮件:“user@example.com”, 密码:“foobar”,password_confirmation:“foobar”)
=> #
IRB(主):002:0>的 user.save
上插入
(0.3ms)SAVEPOINT active_record_1用户存在(0.3ms)SELECT 1 AS一个FROM“users”WHERE LOWER(“users”。“email”)= LOWER('user@example.com')LIMIT 1二进制数据 已在string
列password_digest
类型SQL(48.2ms) INSERT INTO“users”(“created_at”,“email”,“name”,“password_digest”, “updated_at”)VALUES(?,?,?,?,?)[[“created_at”,2013年8月21日,星期三 21:45:13 UTC +00:00],[“email”,“user@example.com”],[“名称”,“示例 用户“],[”password_digest“, “$ 2A $ 10 $ 6tJCohmi7t3OShf / 55S5Se98JWvGhJfC1wNAZsc8B6WPP1Zgee0wu”], [“updated_at”,星期三,2013年8月21日21:45:13 UTC +00:00]]
(0.2ms)RELEASE SAVEPOINT active_record_1 =>真的
IRB(主):003:0> found_user = User.find_by_email(user.email)
用户加载(0.5ms)SELECT“users”。* FROM“users”WHERE“users”。“email”=“user@example.com”LIMIT 1 => #
IRB(主):004:0> user == found_user.authenticate(user.password)
=>真
这就是我在spec / models / user_spec.rb
中的内容require 'spec_helper'
describe User do
before { @user = User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar") }
subject { @user }
.
.
.
describe "return value of authenticate method" do
before { @user.save }
let(:found_user) { User.find_by_email(@user.email) }
describe "with valid password" do
it { should == found_user.authenticate(@user.password) }
end
describe "with invalid password" do
let(:user_for_invalid_password) { found_user.authenticate("invalid") }
it { should_not == user_for_invalid_password }
specify { user_for_invalid_password.should be_false }
end
end
.
.
.
end
用户模型如下
class User < ActiveRecord::Base
before_save { |user| user.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
end
不确定宝石是否重要,这就是我的宝石:
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.0'
group :development do
gem 'annotate', '~> 2.4.1.beta'
end
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'
# Bootstrap css framework from Twitter
gem 'bootstrap-sass', '2.0.0'
# RSpec testing framework
gem 'rspec-rails', '2.11.0'
gem 'capybara', '2.1.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'
group :doc do
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', require: false
end
# Use ActiveModel has_secure_password
gem 'bcrypt-ruby', '3.0.1'
提前感谢您,如果我错过任何其他重要信息,请告诉我。
答案 0 :(得分:2)
您遇到的直接问题是如何设置测试。主题被设置为对象的未保存实例化。如果您在before { subject.reload }
后执行@user.save
,那么就可以解决此问题。那真是个傻瓜。
真正的问题是你过于复杂你的规范。您可以在三种不同的状态下以三种不同的方式在三个不同的位置设置相同的用户。这绝不应该发生。
以下是我设置的方法:
require 'spec_helper'
describe User do
describe "#authenticate" do
let(:user) { User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar") }
it "has a valid password" do
user.authenticate("foobar").should be_true
end
it "has invalid password" do
user.authenticate("invalid").should be_false
end
end
end
要记住几个注意事项。
创建尽可能少的对象:您创建的对象越多,不需要的东西或处于错误状态的可能性就越大,您的测试就会失败,甚至更糟糕的是您的测试很脆弱并且意外失败。
单行it
很好,但限制:当您需要进行快速验证时,单行it
块很棒,但您应该谨慎使用它们。如果您发现正在it
中包含describe
块,那么请删除describe
保持简单:尽量不要预先加载测试。当你加载前的可能性超过你正在编写符合数据的测试时。
在http://betterspecs.org/还有很多其他很棒的提示。绝不是以此作为法律,但它确实有一些很好的信息,可以为编写规范奠定良好的基础。
最后,祝你好运,并喜欢写规格!