为什么factory_girl不能为我进行交易操作? -测试后行保留在数据库中 [英] Why isn't factory_girl operating transactionally for me? - rows remain in database after tests

查看:71
本文介绍了为什么factory_girl不能为我进行交易操作? -测试后行保留在数据库中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用factory_girl创建一个具有RSpec的用户"工厂,但是该工厂似乎不是事务性的,并且显然由于测试数据库中先前测试的剩余数据而失败.

I'm trying to use factory_girl to create a "user" factory (with RSpec) however it doesn't seem to be operating transactionally and is apparently failing because of remnant data from previous tests in the test database.

Factory.define :user do |user|
  user.name                   "Joe Blow"
  user.email                  "joe@blow.com" 
  user.password               'password'
  user.password_confirmation  'password'
end

@user = Factory.create(:user)

运行第一组测试就可以了:

Running the first set of tests is fine:

spec spec/ 


...
Finished in 2.758806 seconds

60 examples, 0 failures, 11 pending

一切正常,符合预期,但是再次运行测试:

All good and as expected, however running the tests again:

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的sequence方法来解决此问题:

Since I have a uniqueness constraint on my email field I attempted to fix the problem by using the sequence method of 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数据库,似乎在两次测试之间没有从数据库回退测试用户的行.我认为这些测试应该是事务性的,但对我而言似乎并非如此.

If I look at the /db/test.sqlite3 database it seems that the row for the test user is not being rolled back from the database between tests. I thought that these tests were supposed to be transactional but they don't seem to be so for me.

这将解释为什么测试第一次可以正确运行(如果我清除了数据库),但是第二次却失败了.

This would explain why the test runs correctly the first time (and if I clear the database) but fails the second time.

任何人都可以解释一下我应该进行哪些更改,以确保测试能够以事务方式运行吗?

推荐答案

最后解决了此问题,希望我可以节省六个小时的调试工作,这使我得以解决.

Finally fixed this and I hope I can save someone the six hours of debugging it took me to figure it out.

通过a)幸运并得到一个可以正常工作的代码版本,以及b)将这两组代码剥离下来,这就是我所发现的:

By a) getting lucky and ending up with a version of code that worked and b) stripping both sets of code down this is what I found:

测试失败

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

该交易是由 应做某事" ... 语句定义的.如果在该语句之外实例化工厂,则表明它不是事务性的.

The transaction is defined by the it "should do something" do... statement. If you instantiate the factory outside that statement it turns out not to be transactional.

您还可以将其放在它应该.."块之外,只要它位于之前..结束"块中即可.

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"块中定义用户似乎是有效的.我猜这只能在它应该做..end"块的范围内执行,因此可以正常工作.

On experimenting, it seems to be valid to define a user outside of an "it should do..end" block as long as it's in a "before.. end" block. I guess this is only executed in the scope of the "it should do..end" block and therefore works fine.

[感谢@jdl的建议(也是正确的建议)

[Thanks to @jdl for his (also correct) suggestion]

这篇关于为什么factory_girl不能为我进行交易操作? -测试后行保留在数据库中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆