34

factory_girl を使用して「ユーザー」ファクトリ (RSpec を使用) を作成しようとしていますが、トランザクション的に動作していないようで、テスト データベース内の以前のテストからの残りのデータのために明らかに失敗しています。

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)

テストの最初のセットを実行しても問題ありません。

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 データベースを見ると、テスト ユーザーの行がテスト間でデータベースからロールバックされていないようです。これらのテストはトランザクショナルなものだと思っていましたが、私にはそうではないようです。

これは、テストが最初に正しく実行される理由 (およびデータベースをクリアした場合) を説明しますが、2 回目は失敗します。

テストが確実にトランザクションで実行されるようにするために何を変更する必要があるかを誰か説明できますか?

4

5 に答える 5

52

最終的にこれを修正しました。私がそれを理解するのにかかった 6 時間のデバッグを誰かが節約できることを願っています。

a) 運良く動作するバージョンのコードが得られ、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

トランザクションはit "should do something" do...ステートメントによって定義されます。そのステートメントの外でファクトリをインスタンス化すると、トランザクションではないことがわかります。

「before..end」ブロック内にある限り、「it should..」ブロックの外に置くこともできます。

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」ブロック内にある限り、「it should do..end」ブロックの外でユーザーを定義することは有効であるようです。これは「it should do..end」ブロックの範囲内でのみ実行されるため、正常に動作すると思います。

[@jdl の (これも正しい) 提案に感謝]

于 2010-08-17T02:45:32.027 に答える
21

before :allトランザクションに関する使用とbefore :eachトランザクションの違いに関する私のブログ エントリを参照してください: http://mwilden.blogspot.com/2010/11/beware-of-rspecs-before-all.html 一言で言えば、before :allはトランザクションではなく、そこで作成されたデータはテストの実行後も残ります。

于 2010-12-08T18:43:32.047 に答える
4

spec/spec_helper.rb、次のものが揃っていることを確認してください

RSpec.configure do |config|
  config.use_transactional_fixtures = true
end

これは私にとって問題を解決するようです。

于 2011-09-15T21:51:43.857 に答える
3

の内部にtest/test_helper.rbは、次のものがあることを確認してください。

class ActiveSupport::TestCase
  self.use_transactional_fixtures = true
  #...
end

「フィクスチャ」という名前にもかかわらず、これも同様に機能しfactory_girlます。

于 2010-08-16T21:16:53.370 に答える