2016-04-04 17 views
1

has_many :through rspecと自己双方向の関係をテストしていて、ジョイントレコードがケースから消えてしまいます。もちろん、私はそれぞれの間でDBを掃除しているわけではありません。has_many:rspecの実行時に継承レコードが永続的でない

author.rb

class Author < ActiveRecord::Base 

    has_many :follower_relationships, 
    foreign_key: :follower_id, 
    class_name: AuthorsRelationship, 
    dependent: :destroy 
    has_many :followed_relationships, 
    foreign_key: :followed_id, 
    class_name: AuthorsRelationship, 
    dependent: :destroy 
    has_many :followers, through: :followed_relationships 
    has_many :followeds, through: :follower_relationships 

    def follow(followed) 
    followeds << followed 
    true 
    end 

    def unfollow(followed) 
    !!(follower_relationships.find_by_followed_id(followed).try :destroy) 
    end 
end 

authors_relationship.rb

class AuthorsRelationship < ActiveRecord::Base 
    belongs_to :follower, foreign_key: :follower_id, class_name: Author 
    belongs_to :followed, foreign_key: :followed_id, class_name: Author 

    validate :ensure_different_targets 
    validates_uniqueness_of :followed_id, 
    scope: :follower_id, 
    message: 'is already following the target' 

    private 

    def ensure_different_targets 
    unless follower != followed 
     errors.add(:follower_id, "can't be equal to followed_id") 
    end 
    end 
end 

author_spec.rb

RSpec.describe Author, type: :model do 
    describe Author, '#follow' do 

    before :all do 
     DatabaseCleaner.start 
     @bieber = Author.create!(name: 'Justin Bieber', screen_name: 'justinbieber') 
     @teen = Author.create!(name: 'Aya No', screen_name: 'Ayano2327') 
    end 

    before :each do 
     @bieber.reload 
     @bieber.followers.reload 
     @bieber.followeds.reload 

     @teen.reload 
     @teen.followers.reload 
     @teen.followeds.reload 
    end 

    after :all do 
     DatabaseCleaner.clean 
    end 

    context 'without followers yet' do 
     it 'returns true' do 
     result = @teen.follow @bieber 
     ap AuthorsRelationship.all 
     expect(result).to be true 
     end 

     it 'should be following after call' do 
     ap AuthorsRelationship.all 
     expect(@teen.followeds).to eq [@bieber] 
     end 
    end 
    end 
end 

第二のテストは失敗します。ここで私は私のapからもらった出力です:

[ 
    [0] #<AuthorsRelationship:0x00000002355f00> { 
       :id => 15, 
     :follower_id => 22, 
     :followed_id => 21, 
     :created_at => Mon, 04 Apr 2016 21:25:04 UTC +00:00, 
     :updated_at => Mon, 04 Apr 2016 21:25:04 UTC +00:00 
    } 
] 
.[] 

この投稿rspec testing has_many :through and after_save問題が解決しませんでした。

答えて

1

before :allはDatabaseCleanerでは信頼性が低く、実際には各テスト間でデータが消去されている可能性があります。

また、これは、テストを互いに完全に独立させておくのがよい方法の例です。与えられたテストケースは、スイート内の他のテストの状態や出力に依存してはいけません。ここではそうではありません。また、RSpecテストはランダムな順序で実行できます。したがって、たとえあなたのコードが期待どおりに動作したとしても、毎回渡すことはできません。

元のbefore :allbefore :eachに置き換え、@teen.follow(@bieber)行をbefore :eachに抽出すると、問題が解決するはずです。また、設定を確認してください。トランザクションフィクスチャを使用していますか? spec_helperファイルでデータベースクリーナーの設定はどのようになっていますか?あなたのコメントパー

EDIT

、私は、データベーストランザクションとテストの間でデータベースを清掃をお勧めしたい:

私は私のために働くために、以下の設定を見つけた:

config.before(:suite) do 
    DatabaseCleaner.clean_with :truncation 
end 

config.after(:suite) do 
    DatabaseCleaner.clean_with :truncation 
end 

config.after(:all, type: :feature) do |example| 
    DatabaseCleaner.clean_with :truncation 
end 

config.before(:each) do |example| 
    DatabaseCleaner.strategy = if example.metadata[:js] 
           :truncation 
           else 
           :transaction 
           end 

    DatabaseCleaner.start 
end 

config.after(:each) do 
    DatabaseCleaner.clean 
end 
+0

ここに私のspec_helper.rbです: config.before(:スイート)は、今アップフロント エンド#クリーンスイート:トランザクション DatabaseCleaner.clean_with(削除) DatabaseCleaner.strategy =を行います – jgburet

+0

DatabaseCleanerについてすべてを削除し、ベースを落としてテストを実行しても、同じ方法で失敗します。 – jgburet

+0

これは意味があります。問題は、データベースクリーナーではありません。 2番目のテストでは、次のような関係は決して設定されていないようです。 2回目のテストの初めに '@teen.follow @ bieber'を追加するとあなたに何が与えられますか? –

1

アンソニーによれば、私はテストを分けました。私はその行動に失望しているだけです。ここに私のコードは今です:

RSpec.describe Author, type: :model do 
    describe Author, '#follow' do 

    before :each do 
     @bieber = Author.create!(name: 'Justin Bieber', screen_name: 'justinbieber') 
     @teen = Author.create!(name: 'Aya No', screen_name: 'Ayano2327') 
    end 

    context 'when already following' do 
     before :each do 
     @teen.follow @bieber 
     end 

     it 'should raise when called' do 
     expect { @teen.follow @bieber }.to raise_error(ActiveRecord::RecordInvalid) 
     end 

     it 'should have made the teen follow bieber' do 
     expect(@teen.followeds).to eq [@bieber] 
     end 

     it 'should have made bieber followed by the teen' do 
     expect(@bieber.followers).to eq [@teen] 
     end 
    end 
    end 
end 
関連する問題