RSpec测试控制器调用CSVCreator报方法调用0次错误如何解决
测试报错原因及修正方案
核心报错原因
- 类方法与实例方法的mock对象错误
你定义的csv_creator = double("CSVCreator")是CSVCreator实例的测试替身,但是new是CSVCreator类本身的静态方法,你把new的调用预期挂到实例替身上,控制器调用的是真实CSVCreator类的new,当然不会触发这个预期。 - 自定义的people替身没有注入到控制器
测试里创建的people = double("People")和控制器实际使用的people集合完全无关,控制器的people是业务逻辑查询得到的真实数据,参数匹配不上,所以预期的调用永远不会被命中。 - 方法链mock逻辑缺失
CSVCreator.new(people).create是链式调用,你stub的new方法没有返回可以响应create的实例替身,就算new被命中,后续调用也会报错。 - 方法名不匹配问题
你提供的CSVCreator类中定义的是generate方法,但控制器调用的是create方法,如果不是笔误的话这也是业务代码的潜在问题,你可以先确认两处方法名是否统一。
修正后的测试代码
it "calls CSVCreator when get request is made" do # 1. 先stub控制器的people方法,返回我们控制的测试集合 test_people = [double(Person, name: "张三", date: "2024-01-01", title: "工程师")] allow(controller).to receive(:people).and_return(test_people) # 2. 创建CSVCreator实例替身,设置预期接收对应方法 csv_creator_instance = double("CSVCreator实例") expect(csv_creator_instance).to receive(:create) # 如果实际方法是generate就改成generate # 3. mock CSVCreator类的new方法,收到test_people参数时返回上面的实例替身 expect(CSVCreator).to receive(:new).with(test_people).and_return(csv_creator_instance) # 4. 发起请求 get :index, format: :csv end
额外优化建议
如果不需要严格校验调用参数,只想验证调用逻辑,可以用receive_message_chain简化写法:
it "calls CSVCreator when get request is made" do allow(controller).to receive(:people).and_return([]) expect(CSVCreator).to receive_message_chain(:new, :create) get :index, format: :csv end
这种写法适合快速验证链式调用,缺点是不会严格校验参数,适合对测试精度要求不高的场景。
内容的提问来源于stack exchange,提问作者waleeeee
相关产品推荐
相关产品推荐

