【问题标题】:Stubbing with Ruby-on-Rails and MiniTest使用 Ruby-on-Rails 和 MiniTest 存根
【发布时间】:2018-11-30 13:06:17
【问题描述】:

我试图了解存根如何与RailsMiniTest 一起工作。我遵循了MiniTest documentation 中的简单示例。我遇到了一个非常简单的例子:

require 'minitest/mock'
require "test_helper"

class TotoTest < ActiveSupport::TestCase

  class Clazz
    def foo
      "foo"
    end
  end

  test "Stubbing" do
    puts Clazz.new.foo # "foo" is well printed
    Clazz.stub :foo, "bar" do # ERROR HERE
      assert_equal "bar", Clazz.new.foo
    end
  end
end

存根时,告诉方法foo 时出现错误。完整的执行日志:

Testing started at 13:55 ...
[...]
Started

foo

Minitest::UnexpectedError: NameError: undefined method `foo' for class `TotoTest::Clazz'
    test/models/toto_test.rb:14:in `block in <class:TotoTest>'
test/models/toto_test.rb:14:in `block in <class:TotoTest>'
Finished in 0.52883s
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips

Process finished with exit code 0

我无法理解为什么在前一行运行良好时我被告知foo 方法不存在。

我错过了什么?为什么这不起作用?

我什至尝试过使用模拟的替代方法:

require 'minitest/mock'
require "test_helper"

class TotoTest < ActiveSupport::TestCase

  class Clazz
    def foo
      "foo"
    end
  end

  test "Stubbing" do
    mock = Minitest::Mock.new
    def mock.foo
      "bar"
    end

    puts Clazz.new.foo
    Clazz.stub :foo, mock do
      assert_equal "bar", Clazz.new.foo
    end
  end
end

结果是一样的。我哪里错了?

编辑:用例

更准确地说,我想存根 YouTube API。对 YouTube API 的调用在一个模块中实现。该模块包含在控制器中。在系统测试中,我想用一个存根替换对该 API 的实际调用,以独立于 YouTube API。

【问题讨论】:

  • 可能希望查看webmock 以获取存根 HTTP 请求。如果您想记录请求并多次重复使用它,也许vcr
  • 我最好避免在非绝对必要时使用任何依赖项 (KISS)。无论如何感谢您的提示。
  • 存根网络请求绝非易事。如果它适用于您的测试,那很好,但是网络请求有很多细微差别,如果您依赖于存根类的 YouTube api 的规范发生变化,将使用过期的 vcr 录制来掩盖这一点。

标签: ruby-on-rails ruby minitest stub


【解决方案1】:

您正在存根类方法而不是实例方法:

Clazz.stub :foo, "bar"

您在常量Clazz 引用的Class 类的实例上调用stub

您应该在 Clazz 实例上调用 #stub

clazz = Clazz.new
clazz.stub :foo, mock do
  assert_equal "bar", clazz.foo
end

编辑: 关于用例。我认为控制器是包含处理外部 API 的方法的错误位置。我建议将它包装在一个单独的对象中,然后你可以存根这个对象,例如:

yt_mock = ... # mocking yt methods you want to use
YouTube.stub :new, yt_mock do
  # controler test
end

您还可以将 YouTube 创建为一个接受适配器并将调用委托给它们的类 - 一个适配器将使用真正的 YT api,另一个只是预定义的答案。

【讨论】:

  • 有没有办法存根该类的所有未来实例?在文档中,我认为这是可能的:Time.stub :now, Time.at(0) do
  • 有一个gem 似乎正在这样做。 IMO 对任何实例进行 Stub 可能是代码异味,如果您这样做,您可能应该重新考虑您的设计。
  • 你是正确的代码气味。我没有使用RSpec,而是MiniTest。我已经用真实的用例更新了我的问题。您对这些新元素有什么建议吗?
猜你喜欢
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 2014-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
相关资源
最近更新 更多