Rspec 限制方法的重用

Rspec limit reuse of methods

Ruby 和 RSpec 的新手所以请保持温柔。

我来自 Python 世界,特别是 pytest。您可以在 pytest 中做的一件事是在您的测试和其他固定装置中使用固定装置。在一个超简单的示例中,假设我们有一个 create 灯具,以及一个需要 createdelete 灯具。如果我们有一个同时使用 createdelete 固定装置的测试,create 只会被调用一次(即使 delete 使用 create,pytest 知道它是已经调用了测试用例。这是一些示例 python 代码:

# test_fixture_reuse.py
import pytest

@pytest.fixture
def create_something():
    """Create tester object"""
    #return MyTester(request.param)
    print ("created_something")


@pytest.fixture
def delete_something(create_something):
    """Create tester object"""
    #return MyTester(request.param)
    print ("delete_something")


class TestIt:
    def test_only_create(self, create_something):
        print ("in test_only_create")
        assert 1

    def test_create_and_delete(self, create_something, delete_something):
        print ("in test_create_and_delete")
        assert 1

    def test_only_delete(self, delete_something):
        print ("in test_only_delete")
        assert 1

运行 pytest -v test_fixture_reuse -s returns 这个输出,和预期的一样:

test_parameterized_fixture.py::TestIt::test_only_create created_something
in test_only_create
PASSED
test_parameterized_fixture.py::TestIt::test_create_and_delete created_something
delete_something
in test_create_and_delete
PASSED
test_parameterized_fixture.py::TestIt::test_only_delete created_something
delete_something
in test_only_delete
PASSED

根据我在 Ruby 中的尝试,没有与 fixture 等效的概念,这意味着每个测试都需要控制调用流。因此,如果我们正在测试删除,测试将需要调用 create,然后调用 delete,但 delete 不会显式依赖于 create。 RSpec 中的灯具通常似乎映射到模型,因此大多数搜索结果都不相关。

我的问题是 - 我怎样才能在 RSpec 中执行类似于上述 python 代码的操作?还是因为 Python 的经验,这是我的观点过于局限的事情之一,并且在 RSpec 中有一种类似的做事方式我没有正确搜索?

在 RSpec 中我们使用 let 作为记忆辅助方法,像这样:

RSpec.describe("my tests") do
  let(:created_record) { MyRecord.create }

  # using tap here to return the deleted record from the block
  let(:destroyed_record) { created_record.tap(&:destroy) } 

  it("can create record") { created_record }
  it("can destroy record") { destroyed_record }
  it("memoizes created_record if called twice") { created_record; destroyed_record }
end

let 调用不会 运行 直到您第一次在测试中引用它们,并在该测试用例中为后续调用使用缓存的结果。 “测试用例”是指 it 块。如果您希望这些方法在每个测试用例开始时自动执行(无需显式调用该方法),您可以改用 let!。结果仍将被缓存以供后续调用。参见 https://relishapp.com/rspec/rspec-core/v/2-11/docs/helper-methods/let-and-let

subject https://relishapp.com/rspec/rspec-core/v/3-10/docs/subject 也值得一读。

如果您想要一个普通的、未缓存的方法,您只需编写一个常规的 def .. end。参见 https://relishapp.com/rspec/rspec-core/v/3-10/docs/helper-methods/arbitrary-helper-methods

另一件事,Rails 土地中的术语“fixture”有一些特定的含义,它通常意味着您从 YAML 文件或类似文件加载数据库状态(参见 https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures) ... this is in contrast to "factories" which are much easier to work with but also significantly slower (see https://github.com/thoughtbot/factory_bot 这是制造工厂最常用的库)。