Rails 请教如何针对 model 中的 validates 进行测试

helperhaps · 2015年08月19日 · 最后由 helperhaps 回复于 2015年08月20日 · 2071 次阅读

在 table 的 model 中有如下的 validates,要求在创建 table 的时候 name 不能重复,

validates :name, presence: true, uniqueness: true

这个帮助方法会在保存对象之前验证属性值是否是唯一的。该方法不会在数据库中创建唯一性约束,所以有可能两个数据库连接创建的记录字段的值是相同的。为了避免出现这种问题,要在数据库的字段上建立唯一性索引——Rails Guides(uniqueness)

由于上述原因,在数据库的相应字段上建立了唯一性索引后其 schema 中出现如下的一行:

add_index "tables", ["name"], name: "index_tables_on_name", unique: true, using: :btree 

那么问题来了,如何对这个验证操作编写测试用例(rspec)?前辈们有什么可行的方案吗?

你要验证哪个?model 里的这个 validation 还是 add_index 这句 ?

#1 楼 @prajnamas 多谢回复,在下去看看文档先

#2 楼 @raven ,谢谢回复,在下需要验证的是加了唯一性索引之后的被 uniqueness 修饰的 column 的值是否还会重复,即解决正文中引用的 Rails Guides 中所说的那种情况(两个数据库连接创建的记录字段的值是相同的)是否能成功被避免,这样说来的话,应该就是有 add_index 的 validates,所以重点是要在 rspec 中构造两个数据库连接,再并发执行?

#4 楼 @helperhaps 不用那么麻烦 你先创建一条记录 然后再用 RAW SQL 之类的可以跳过 uniqueness validation 的方法再插入 name 和刚才那个记录一样的数据 然后断言这个操作不能成功就可以了

#5 楼 @raven 👍 听君一席话,胜读十年书啊,

#1 楼 @prajnamas 这个 gem 包貌似有些旧,但也不知道为什么就是运行不成功,但还是多谢你的回答

一般来说,rails 自己的功能是不需要你来测试的,因为 rails 本身已经测试过了. 所以,你只需要测试你自己的业务逻辑. 这事隐约记得 DHH 自己也说过。

#7 楼 @ch3n 谢谢回复,其实在下也是这么想的,rails 和 mysql 的业务逻辑(应该是经过无数次测试和实践检验过的)要是还需要自己来测试的话,,,再次感谢站在我的这边 😄 ,但在下不才争不过项目组长 😭

理论上应用里面的唯一性检查不是百分百覆盖的,但实际上真正需要用到数据库检查的机会极少极少。

你想一想,假设在一个进程处理相关请求的时间是 100ms, 你能有多少机会见到两个或更多的请求在同一时间段内需要同样的 name 值呢?

这种情况我们还真遇见过,还不是一次两次,以至后端同事讨论要不要加数据库限制。后来发现是前端的一个按钮在按下后没有禁用导致重击,所以在极短时间内有重复内容的请求。前端简单解决后再无此问题。

你可能觉得这样双保险是为了严谨。但严谨也不是免费的。索引要占空间,可能影响速度,还要写 migration。如果每个此类需求都要这么做,需要加多少东西。

再想想,你不一定真的需要这么写。

#9 楼 @billy 感谢回复,你的说法有一定的道理,虽然是否需要在数据库层面添加唯一性约束不是这个帖子的初衷,但是在下觉得,要是遇到别有用心的用户,他可以跳过前端的解决方式的话(虽然这种可能比较小,但未必不可能,或许有技术人员为了打发无聊),岂不是会影响我们的系统,在下个人觉得不能因为发生的机会少就不去考虑这种情况(或许有些小题大作),即使牺牲一部分性能,当然,要是内部网的话,那应该就没啥子问题,你说呢

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