В пользовательской модели у меня есть следующие методы:
def generate_and_set_new_password!
password = random_pronouncable_token
self.password_hash = encrypt(password)
self.password_reset_sent_at = Time.now
if self.save!
password
else
nil
end
end
private
def encrypt(string)
# Some code that encrypts string
# ...
end
def random_pronouncable_token(size = 4)
# Some code that generates new password
# ...
end
Тест rSpec:
describe "New password generation" do
it "should generate new password" do
user = @user
old_pwd_hash = user.password_hash
pwd = user.generate_and_set_new_password!
pwd.should_not be_nil
user.password_hash.should_not == old_pwd_hash
end
end
Этот тест дает мне такой вывод:
1) User password encryption New password generation should generate new password
Failure/Error: user.password_hash.should_not == old_pwd_hash
expected not: == "966abfff742d73c71fc87a1928b90aec"
got: "966abfff742d73c71fc87a1928b90aec"
'generate_and_set_new_password!'метод правильно работает в приложении, вот пример из консоли:
ruby-1.8.7-p249 :014 > user.password_hash
=> "ef10fb44dfceeaca05ca78030c1d8cb5"
ruby-1.8.7-p249 :015 > user.generate_and_set_new_password!
=> "quispopeho"
ruby-1.8.7-p249 :016 > user.password_hash
=> "a0b7605d5d6ca2152f7e019b4896fef4"
ruby-1.8.7-p249 :017 >
Как мы видим, он дает новый password_hash для пользователя, поэтому он работает правильно.
Я решил, что этокакая-то ошибка в rSpec.Я провел такой эксперимент:
Вот некоторые изменения в коде теста:
describe "New password generation" do
it "should generate new password" do
user = @user
old_pwd_hash = user.password_hash
p "old_password = ", user.password
p "old_pwd_hash = ", old_pwd_hash
pwd = user.generate_and_set_new_password!
p "received new password = #{pwd}"
p "SHOULD BE a new_pwd_hash, but it isn't! ", user.password_hash
p "SHOULD BE a new_password, but it isn't! ", user.password
pwd.should_not be_nil
# There I am tring to set this new password explicitly :)
user.password = pwd
user.save
p "NOW it is other password hash = ", user.password_hash
user.password_hash.should_not == old_pwd_hash
end
end
Теперь тест пройден!
И вывод отладки следующий:
"old_password = foobar"
"old_pwd_hash = c251e8a9bcc4fba1199181b1f2c1430c"
"received new password = kongibyty"
"SHOULD BE a new_pwd_hash, but it isn't! c251e8a9bcc4fba1199181b1f2c1430c"
"SHOULD BE a new_password, but it isn't! foobar"
"NOW it is other password hash = e2b53133b796bcb212a0c1fa1d2a1cfa"
Как видно из этого отладочного вывода, пользовательский объект получает свой новый password_hash ТОЛЬКО после того, как он ЯВНО был установлен в коде теста.Похоже, «генерировать_и_сет_new_password!»Метод не может изменить объект, созданный в тестовой среде.
Почему я получаю такое странное поведение rSpec?Любые предложения будут полезны.
Дополнительная информация о моей среде разработки:
Я использую:
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
Rails 3.0.9
rvm
Фрагмент Gemfile:
group :development, :test do
gem "rspec-rails", "~> 2.6"
gem 'webrat', '0.7.1'
gem 'spork', '0.9.0.rc9'
gem 'autotest-standalone'
gem 'autotest', '4.4.6'
gem 'autotest-rails-pure', '4.1.2'
gem 'factory_girl_rails', '1.0'
end
Udpates:
Код, который создает @ user
require 'spec_helper'
describe User do
# attributes for user object
before(:each) do
@attr = {
:email => "user@example.com",
:password => "foobar",
:password_confirmation => "foobar",
:first_name => "Example",
:last_name => "Examploid",
:dob => Date.new(1980,07,03),
:relationships_status => "Single",
:sex => "male",
:sexual_orientaion => "Woman",
:about_me => "All about me",
:school_id => 1,
:education_id => 1,
:occupation_id => 1,
:web_site => "example.com"
}
end
# Some other tests...
# ...
describe "password encryption" do
# create user
before(:each) do
@user = User.create!(@attr)
end
# Some other tests...
# ...
# Here is shown the same test code as above.
describe "New password generation" do
it "should generate new password" do
# I even tried to use factory_girl's method
# @user = Factory(:device_user)
user = @user
old_pwd_hash = user.password_hash
pwd = user.generate_and_set_new_password!
pwd.should_not be_nil
user.password_hash.should_not == old_pwd_hash
end
end
end
end
Некоторые пояснения:
Я не использую заглушки@ методы пользователя в любом из моих тестов.
Я попытался сделать то же самое с factory_girl, и получил тот же тест, не пройдя.Вот фабричное определение пользователя:
Factory.define :device_user, :class => User do |user|
user.password "password"
user.password_confirmation "password"
user.email "device_user@example.com"
user.first_name "Device"
user.last_name "User"
user.dob Date.new(2011,10,03)
user.relationships_status "Single"
user.sex "male"
user.sexual_orientaion "Woman"
user.about_me "All about Device User"
user.school_id 1
user.education_id 1
user.occupation_id 1
user.web_site "device.example.com"
user.facebook_id "face_test_id"
end