Почему для меня нет транзакции factory_girl? - строки остаются в базе данных после тестов
Я пытаюсь использовать factory_girl для создания "user" factory (с RSpec), однако он, похоже, не работает транзакционно и, по-видимому, не работает из-за остаточных данных предыдущих тестов в тестовой базе данных.
Factory.define :user do |user|
user.name "Joe Blow"
user.email "[email protected]"
user.password 'password'
user.password_confirmation 'password'
end
@user = Factory.create(:user)
Запуск первого набора тестов в порядке:
spec spec/
...
Finished in 2.758806 seconds
60 examples, 0 failures, 11 pending
Все хорошее и, как ожидалось, однако снова запускает тесты:
spec spec/
...
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/validations.rb:1102:in `save_without_dirty!': Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/dirty.rb:87:in `save_without_transactions!'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:182:in `transaction'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!'
from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/proxy/create.rb:6:in `result'
from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/factory.rb:316:in `run'
from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/factory.rb:260:in `create'
from /Users/petenixey/Rails_apps/resample/spec/controllers/users_controller_spec.rb:7
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:183:in `module_eval'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:183:in `subclass'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:55:in `describe'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_factory.rb:31:in `create_example_group'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/dsl/main.rb:28:in `describe'
from /Users/petenixey/Rails_apps/resample/spec/controllers/users_controller_spec.rb:3
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:147:in `load_without_new_constant_marking'
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:147:in `load'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:15:in `load_files'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `each'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `load_files'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.rb:133:in `run_examples'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/command_line.rb:9:in `run'
from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/bin/spec:5
from /usr/bin/spec:19:in `load'
from /usr/bin/spec:19
Исправить попытку - используйте Factory.sequence
Поскольку у меня есть ограничение уникальности в моем поле электронной почты, я попытался исправить эту проблему, используя метод последовательности factory_girl:
Factory.define :user do |user|
user.name "Joe Blow"
user.sequence(:email) {|n| "joe#{n}@blow.com" }
user.password 'password'
user.password_confirmation 'password'
end
Затем я запустил
rake db:test:prepare
spec spec/
.. # running the tests once executes fine
spec spec/
.. # running them the second time produces the same set of errors as before
Пользователи, похоже, остаются в базе данных
Если я смотрю на базу данных /db/test.sqlite3, кажется, что строка для тестового пользователя не откатывается из базы данных между тестами. Я думал, что эти тесты должны быть транзакционными, но они, похоже, не так для меня.
Это объясняет, почему тест выполняется правильно в первый раз (и если я очищаю базу данных), но не работает во второй раз.
Может ли кто-нибудь объяснить, что я должен изменить, чтобы гарантировать, что тесты выполняются транзакционно?
Ответы
Ответ 1
Наконец, исправил это, и я надеюсь, что смогу спасти кого-то шесть часов отладки, которые потребовались мне, чтобы понять это.
А) получив удачу и получив версию кода, которая сработала, и b) снятие обоих наборов кода вниз, это то, что я нашел:
Тест, который задыхается
require 'spec_helper'
describe UsersController do
@user = Factory.create(:user)
end
Тест, который работает
require 'spec_helper'
describe UsersController do
it "should make a factory models without choking" do
@user = Factory.create(:user)
end
end
Сделка определяется оператором , который должен сделать что-то "do.... Если вы создаете экземпляр factory вне этого утверждения, он оказывается не транзакционным.
Вы также можете поместить его вне блока "он должен..", если он находится в блоке "before..end"
require 'spec_helper'
describe UsersController do
before(:each) do
@user = Factory.create(:user)
end
it 'should make a factory without choking' do
puts @user.name
# prints out the correnct name for the user
end
end
При экспериментировании кажется правильным определять пользователя за пределами блока "он должен делать..енд", пока он находится в блоке "before.. end". Я предполагаю, что это выполняется только в объеме блока "он должен делать.." и поэтому отлично работает.
[Спасибо @jdl за его (также правильное) предложение]
Ответ 2
Смотрите мою запись в блоге о различии между использованием before :all
и before :each
в отношении транзакций: http://mwilden.blogspot.com/2010/11/beware-of-rspecs-before-all.html. В двух словах, before :all
не является транзакционным, и создаваемые там данные будут всплывать после запуска теста.
Ответ 3
В spec/spec_helper.rb
убедитесь, что у вас есть следующие
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
Это, похоже, решает проблему для меня.
Ответ 4
Внутри test/test_helper.rb
убедитесь, что у вас есть следующее.
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
#...
end
Несмотря на название "светильники", это работает также с factory_girl
.
Ответ 5
Я столкнулся с этими же симптомами при обновлении проекта с Rails 3 до Rails 4. Я сделал установку пакета, и режим разработки, казалось, работал нормально, но я не получил бы транзакционного поведения в тестах. Оказывается, выполнение обновления пакета решает проблему.