tdg*_*dgs 29 ruby rspec transactions ruby-on-rails rails-activerecord
我有一个模型功能,我想确保使用一个事务.例如:
class Model
def method
Model.transaction do
# do stuff
end
end
end
Run Code Online (Sandbox Code Playgroud)
我当前的方法是在块内部存根方法调用以引发ActiveRecord::Rollback
异常,然后检查数据库是否实际已更改.但这意味着如果由于某种原因,块内的实现发生了变化,那么测试就会中断.
你会怎么测试这个?
emr*_*ass 33
您应该从不同的角度来看问题.从行为角度来看,测试函数是否使用事务是无用的.它没有提供有关函数BEHAVES是否符合预期的任何信息.
您应该测试的是行为,即预期结果是正确的.为清楚起见,假设您在函数内执行操作A和操作B(在一个事务中执行).操作A将用户100美元记入您的应用程序.B行动用100美元借记用户信用卡.
您现在应该为测试提供无效的输入信息,以便从用户信用卡中扣款.将整个函数调用包装在一个expect { ... }.not_to change(User, :balance)
.
这样,您可以测试预期的行为 - 如果信用卡借记失败,请不要将该金额记入用户.此外,如果您只是重构代码(例如,您停止使用事务并手动回滚事物),那么测试用例的结果不应受到影响.
话虽这么说,你仍然应该像@luacassus提到的那样孤立地测试这两个操作.此外,如果您将提及的"不兼容"更改(即您更改行为)更改为源代码,那么您的测试用例应该会失败,这是完全正确的,如@ rb512所述.
kon*_*yak 16
需要提到一个很大的问题:在测试事务时,您需要关闭transactional_fixtures.这是因为测试框架(例如Rspec)将测试用例包装在事务块中.永远不会调用after_commit,因为没有真正提交.即使您使用:requires_new => true,期望在事务内部回滚也不起作用.相反,事务在测试运行后回滚.参考http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html嵌套事务.
通常,您应该使用"纯"rspec测试来测试隔离中的应用程序块(类和方法).例如,如果您有以下代码:
class Model
def method
Model.transaction do
first_operation
second_operation
end
end
Run Code Online (Sandbox Code Playgroud)
你应该测试first_operation
,并second_operation
在不同的测试场景,理想而无需访问数据库.稍后您可以编写测试Model#method
并模拟这两种方法.
在下一步,您可以使用https://www.relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec编写高级集成测试,并检查此代码在不同条件下如何影响数据库,例如什么时候second_method
会失败.
在我看来,这是测试生成复杂数据库查询的代码的最实用的方法.
归档时间: |
|
查看次数: |
10270 次 |
最近记录: |