使用RSpec 3.12测试记录失效标记时的异常问题排查
软删除测试问题排查与修复
背景情况
我的Playground控制器采用软删除逻辑:用户删除时不会真正删除记录,只是调用set_as_inactive方法把is_active标记设为false,并记录操作人。控制器代码如下:
def destroy @playground.set_as_inactive(current_login) respond_to do |format| format.html { redirect_to playgrounds_url, notice: t('.Success') } #'Playground was successfully deleted.' format.json { head :no_content } end end
这个功能在实际应用里运行正常,但写请求测试时发现了问题:测试代码中Playground.visible(仅返回活跃记录)的计数确实减了1,但直接检查playground_tbd.is_active却还是true。测试代码如下:
describe "DELETE /destroy" do let(:playground_tbd) { create(:playground) } it "destroys the requested playground" do expect { delete playground_url(playground_tbd) }.to change(Playground.visible, :count).by(-1) expect(response).to have_http_status 302 expect(response).to redirect_to(playgrounds_url) end it "renders the expected status" do get playground_url(playground_tbd) expect(playground_tbd.is_active).to eq(false) end end
问题根源
你漏了两个关键细节:
第二个测试没执行删除操作
RSpec的每个it块都是独立运行的,彼此之间数据库状态会回滚重置。第二个测试里只执行了get请求,根本没调用DELETE接口去标记记录失效,所以playground_tbd还是刚创建时的活跃状态。内存对象不会自动同步数据库变更
就算你在测试里执行了DELETE操作,内存里的playground_tbd对象也不会自动更新,必须调用reload方法从数据库重新读取,才能拿到最新的is_active值。
修正后的测试代码
describe "DELETE /destroy" do let(:playground_tbd) { create(:playground) } it "destroys the requested playground" do expect { delete playground_url(playground_tbd) }.to change(Playground.visible, :count).by(-1) expect(response).to have_http_status 302 expect(response).to redirect_to(playgrounds_url) end it "marks the playground as inactive" do # 先执行软删除操作 delete playground_url(playground_tbd) # 重新加载对象获取数据库最新状态 playground_tbd.reload expect(playground_tbd.is_active).to eq(false) end end
额外说明
- 每个测试用例都是独立的,前一个测试的数据库变更会被回滚,所以第二个测试的
playground_tbd是全新的活跃记录。 - 控制器修改数据库后,内存中的对象实例不会自动同步,必须用
reload才能验证最新属性。
内容的提问来源于stack exchange,提问作者user1185081
相关产品推荐
相关产品推荐

