如何stub Active Storage URL以在Rails系统测试中规避S3请求?
你之前的写法出现报错,是因为两个核心问题:
- 你只给
User#photo返回的桩对象定义了url方法,但视图中调用了@user.photo.variant(),这个桩对象没有对应的variant方法,也不支持url_for要求的to_model协议,触发了未定义方法的报错。 - 你stub的层级不对,
url_for最终调用的是Active Storage变体实例的url方法,不需要替换整个photo关联对象。
正确解决方法
方案1:全局stub Active Storage变体的url方法(最省事,适合所有需要替换变体URL的场景)
直接对ActiveStorage::Variant的url方法打桩,所有变体的URL都会直接返回你指定的本地路径,完全不需要修改原有业务代码:
class UserPageTest < ApplicationSystemTestCase test "thumbnail appears on user page" do # 所有变体的url直接返回占位图路径 ActiveStorage::Variant.any_instance.stubs(:url).returns("/test_data/placeholder_thumbnail.jpg") # 如果还要覆盖非变体的原附件URL,加下面这行 ActiveStorage::Blob.any_instance.stubs(:url).returns("/test_data/placeholder.jpg") visit '/user_profile/123' # 后续你的断言逻辑 end end
这种写法保留了Active Storage原有对象的所有接口,完全满足url_for的调用要求,不会出现方法缺失的报错。
方案2:针对单个实例精准打桩(避免全局桩的副作用)
如果你不想全局影响所有变体的URL,可以针对单个测试用户的photo关联打桩,给桩对象补上url_for需要的to_model方法:
class UserPageTest < ApplicationSystemTestCase test "thumbnail appears on user page" do # 先创建/获取测试用户 test_user = User.find(123) # 构造符合要求的变体桩 variant_stub = stub( to_model: self, # 满足url_for的协议要求 url: "/test_data/placeholder_thumbnail.jpg" ) # stub photo的variant方法返回上面的桩 test_user.photo.stubs(:variant).returns(variant_stub) visit '/user_profile/123' # 后续你的断言逻辑 end end
额外注意
如果你的Rails版本中url_for调用的是service_url而不是url,同步stub对应的service_url方法即可:
ActiveStorage::Variant.any_instance.stubs(:service_url).returns("/test_data/placeholder_thumbnail.jpg")
内容的提问来源于stack exchange,提问作者dB'
相关产品推荐
相关产品推荐

