我正在测试我的has_many :through
- 与rspec的自我双向关系,我的联合记录只是从一个案例消失到另一个案例。当然,我毕竟不是在每个之间清理数据库。
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
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
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
}
]
.[]
答案 0 :(得分:1)
before :all
并不可靠,因此您的数据可能在每次测试之间实际被擦除。
此外,这是一个为什么保持测试完全独立的一个例子,这是一个很好的做法。给定的测试用例不应该依赖于套件中任何其他测试的状态或输出,这不是这里的情况。还要记住,RSpec测试可以按随机顺序运行。因此,即使您的代码按预期工作,也可能不会每次都通过。
我会将原before :all
替换为before :each
并将@teen.follow(@bieber)
行提取到before :each
,这应该可以解决问题。另请检查您的配置。你在使用交易设备吗?您的spec_helper
文件中的数据库清理程序配置是什么样的?
修改强>
根据您的评论,我建议在使用数据库事务的测试之间清理数据库:
我发现以下配置对我有用:
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
答案 1 :(得分: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