新手问题 测试一个组合的唯一性,我在数据库层面增加了组合 unique 但是测试有问题

yirolhao · 2017年02月28日 · 最后由 yirolhao 回复于 2017年02月28日 · 1958 次阅读

测试一个组合的唯一性,我在数据库层面增加了组合 unique。 但是测试有问题:

def setup
  @like = Like.new(liker_id: 1, liked_article_id: 1)
end

test "liker-id and liked-article-id unique" do
  assert @like.valid? 
  assert @like.save
  @other = @like.dup
  assert_not @other.save
end

没有通过,但是在 Rails Console 中可以:

@like = Like.new(liker_id: 1, liked_article_id: 1)
@like.valid?
@like.save 
@other = @like.dup
@other.save #失败

like.rb

class Like < ApplicationRecord
  belongs_to :liker, class_name: "User"
  belongs_to :liked_article, class_name: "Article"
  validates :liker_id, presence: true
end

之前运行测试的时候出现了错误,让我运行 rails env=test 或者 env=development 大概这样,记不清了。 我运行了第一个,然后执行了迁移。

--------------------------------解决 按照 @lithium4010 说的:

liker liked article 必须关联上

测试环境数据库没有 id 为 1 的 liker 和 liked_article

进行如下修改:

def setup
  @user = User.create(name:"kaka",email: "[email protected]",
                          password_digest: User.digest('password'))
  @article = @user.articles.create(title: "mysq",content: "kakarot")
   @like = Like.new(liker_id: @user.id, liked_article_id: @article.id)
end

test "liker-id and liked-article-id unique" do
    Like.destroy_all
    assert @like.valid? 
    assert @like.save
    @other = Like.new(liker_id: @user.id, liked_article_id: @article.id)
    assert_not @other.save
    assert @user.destroy
    assert @article.destroy
end

原谅我不知道这里固件应该怎么用。

感谢 @kai209209 @lithium4010

你 model 的代码不发出来看看吗

kai209209 回复

好,但是我的 model 其实没有什么东西的。

你这 model 只是定义了 like_id 必须存在,并没有组合唯一性的代码

kai209209 回复

但是 assert @like.valid? 也没有通过。

你添加这个代码

validates :liker, uniqueness: { scope: :liked_article}


然后测试一下

kai209209 回复

没有用,还是没通过,这个是什么意思?我没有 liker 这一列

like 就是 like_id 啊

完整的写就是这样:validates :liker_id, uniqueness: { scope: :liked_article_id}

_id 可以省

kai209209 回复

但是验证还是没有办法通过。

yirolhao 回复

你测试数据库表里面的数据在你测试完后会自动删除掉数据吗?

kai209209 回复

应该是不会自动删除,因为 demo_test 数据库里 users 表里面有数据,但是 likes 表里面没有数据。

我刚刚新建了一个跟你一样代码的项目做了测试,似乎就是你测试数据库里的 like 表的数据没有清除导致的。 like 里面添加 validates :liker_id, uniqueness: { scope: :liked_article_id} 然后我这里测试通过了

yirolhao 回复

你测试改这样

def setup
  @like = Like.new(liker_id: 1, liked_article_id: 1)
end

test "liker-id and liked-article-id unique" do
  Like.destroy_all
  @like.valid?
  assert @like.valid? 
  assert @like.save
  @other = Like.new(liker_id: 1, liked_article_id: 1)
  assert_not @other.save
end
kai209209 回复

但我的 likes 表是空的,我看了 test 数据库。或者怎么样在清除一次?reset?

kai209209 回复

还是不行。。😭 😭 还是原来的错误,都是 false 这样才能通过。

Like.destroy_all
assert_not @like.valid? 
assert_not @like.save
@other = Like.new(liker_id: 1, liked_article_id: 1)
assert_not @other.save

会不会是我选择 env 的问题?

yirolhao 回复

你改成这样

test "liker-id and liked-article-id unique" do
  Like.destroy_all
  @like.valid?
  p "111!!!!#{@like.valid?}"
  assert @like.valid? 
  assert @like.save
  p "2222!!!!!#{@like.attributes}"
  @other = Like.new(liker_id: 1, liked_article_id: 1)
  p "3333!!!!#{@other.valid?}"
  p "4444!!!!#{@other.errors.messages}"
  assert_not @other.save
end

然后看看输出是什么?

我这里输出是这样的

kai209209 回复

rails test 之后,就只 Failure 没有其他错误信息了,话说还能这么用,我一直是在 console 里面,这么看。

p "111!!!!#{@like.valid?}"
p "@like errors: #{@like.errors.messages}"

添加一行,看看输出的是什么错误

kai209209 回复

让通过之后的。

kai209209 回复
"{:liker=>[\"must exist\"], :liked_article=>[\"must exist\"]}"

这不是在 new 的时候都有的吗?。。。

yirolhao 回复
test "liker-id and liked-article-id unique" do
  Like.destroy_all
  @like.valid?
  p "111!!!!#{@like.valid?}"
  p "@like errors: #{@like.errors.messages}"
  assert @like.valid? 
  assert @like.save
  p "2222!!!!!#{@like.attributes}"
  @other = Like.new(liker_id: 1, liked_article_id: 1)
  p "3333!!!!#{@other.valid?}"
  p "4444!!!!#{@other.errors.messages}"
  assert_not @other.save
end

你测试用例改这样啊,看@like输出的的错误是什么

kai209209 回复

我上面那个就是输出的错误,我加了之后的。

你测试数据库迁移了吗?你到命令行下执行 rails db:migrate RAILS_ENV=test,然后再测试

kai209209 回复

对,上次我就运行的这条命令,然后迁移,我在看看

kai209209 回复

运行了,没有任何返回,貌似没有没迁移的文件。运行测试还是如以前一样的结果。😭

你项目里面没有迁移文件的?

kai209209 回复

我的意思是说,所有的文件都已经迁移过了。运行,ails db:migrate RAILS_ENV=test 没有反应。

https://github.com/kai209209/like 我把我做的放到 github 里了,你看看跟你项目的 like 有没有什么区别吧

kai209209 回复

没什么区别,要说区别的话,只有 user 和 article

article.rb

has_many :passive_likes, class_name:  "Like",
                         foreign_key: "liked_article_id",
                         dependent:   :destroy
has_many :liked_article, through: :passive_likes 

user.rb

has_many :active_likes, class_name:  "Like",
                        foreign_key: "liker_id",
                        dependent:   :destroy
has_many :liker, through: :active_likes

liker liked article 必须关联上

测试环境数据库没有 id 为 1 的 liker 和 liked_article

lithium4010 回复

我数据库里也没有 liker 和 liked_article,但是我的能通过

lithium4010 回复

我在回宿舍路上,回去看看。新建一个吗?

yirolhao 回复

你测试里面是不是还有什么别的代码啊?

kai209209 回复

没有,就那个。

yirolhao 回复

不知道你项目具体代码是怎么样的,无法排出问题

kai209209 回复

按照 @lithium4010 他说的,我改了之后好了。

def setup
  @user = User.create(name:"kaka",email: "[email protected]",
                          password_digest: User.digest('password'))
  @article = @user.articles.create(title: "mysq",content: "kakarot")
   @like = Like.new(liker_id: @user.id, liked_article_id: @article.id)
end

test "liker-id and liked-article-id unique" do
    Like.destroy_all
    assert @like.valid?
    assert @like.valid? 
    assert @like.save
    @other = Like.new(liker_id: 1, liked_article_id: 1)
    assert_not @other.save
    assert @user.destroy
    assert @article.destroy
  end
kai209209 回复

不知道固件这里应该怎么用,就只能酱紫了。

难道这个测试还跟数据库有关?我用的是 sqllite3,你这里用的是什么数据库

kai209209 回复

mysql 数据库

yirolhao 回复

有个 gem 可以测试完后自动删除测试数据的,你就不用写个 Like.destroy_all 上去了,而且测试数据一般在测试完后都是要删的

kai209209 回复

哪个 gem?

yirolhao 回复

gem 'database_cleaner' 放到 test 的 group 里面

kai209209 回复

好的,我去看看。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号