测试中存根方法has_salary?行为不一致的原因及解决办法
问题原因与解决方案
为什么行为不一致?
- 你存根的
employee_1、employee_2是内存中已存在的实例对象,存根逻辑仅对这两个特定实例生效。 Employee.first和Employee.second是通过数据库查询重新生成的新实例,它们和你最初创建的employee_1、employee_2是完全不同的对象,没有被应用存根规则,因此会执行has_salary?方法的原始逻辑,返回false。
如何全局存根该方法?
根据需求场景,有两种常用实现方式:
1. 让所有Employee实例返回统一结果
如果需要所有Employee实例调用has_salary?都返回相同值,可以直接存根类的实例方法:
# 所有实例都返回true allow(Employee).to receive(:has_salary?).and_return(true) # 或者根据实例动态返回结果 allow_any_instance_of(Employee).to receive(:has_salary?) do |employee| # 示例:根据实例ID区分返回值 employee.id == employee_1.id ? false : true end
注意:
allow_any_instance_of在RSpec中属于慎用API,因为它会影响所有实例,可能导致测试间的耦合,但简单场景下可以快速实现需求。
2. 让特定数据库记录的实例始终返回指定值(推荐)
更健壮的方式是让has_salary?的逻辑基于实例属性,这样无论从数据库加载多少次,结果都符合预期:
- 先确保
Employee模型的has_salary?方法基于属性判断:
# app/models/employee.rb def has_salary? salary.present? # 假设salary是数据库字段 end
- 创建实例时直接设置对应属性:
employee_1 = create :employee, salary: nil employee_2 = create :employee, salary: 5000
这种方式不需要存根,测试逻辑完全贴合真实业务场景,无论调用内存中的实例还是重新加载的实例,结果都会一致。
内容的提问来源于stack exchange,提问作者mrateb
相关产品推荐
相关产品推荐

