0

我喜欢 Catch 嵌套测试层次结构的方式,它通过组合工作。这感觉比 xUnit 框架的设置/拆卸更自然。

我现在有一组测试。我想做的,大约一半是插入一个加载/保存序列化测试,然后重复该点以下的所有测试,首先没有加载/保存,然后再次使用它从序列化过程加载的数据。即证明加载/保存是正确的。

如果 Catch 有什么可以帮助解决这个问题,我无法理解?如果是 phpUnit,我会考虑一串@depends测试,并使用@dataProvider带有布尔输入的 a。有点丑。

(如果这没有意义,请告诉我,我会尝试做一个最小的例子)

4

1 回答 1

1

这里的问题是,Catch 旨在降低测试的树状组织,它会自动发现结构的所有叶节点,并使用未经测试的代码路径回调到测试用例中,直到它们都经过测试。叶节点(测试,部分)是独立的。

听起来您想测试存储库- 可以保留一些数据然后将其重新加载的东西。

要在两个不同的场景(序列化之前,序列化之后)重复完全相同的测试,您需要将相同的测试放在某个公共位置并调用该位置。您仍然可以在非测试用例函数中使用相同的 Catch 宏,只要您从测试用例调用它。

一种可能的方法是:

struct TestFixture {
  Data data;
  Repository repository;
  TestFixture() : data(), instance() { }
};

void fillUpData(Data& data) {
  // ...
}

void isDataAsExpected(Data& data) {
  // Verify that 'data' is what we expect it to be, whether we
  // loaded it or filled it up manually
  SECTION("Data has ...) {
    REQUIRE(data...);
  }
}

TEST_CASE_METHOD(TestFixture, "Test with raw data") {
  fillUpData(data);
  isDataAsExpected(data);
  REQUIRE(repository.save(data));
}

TEST_CASE_METHOD(TestFixture, "Operate on serialised data") { 
  REQUIRE(repository.load(data));
  isDataAsExpected(_data);
}

一种可能的替代方法是提供您自己的 main 然后使用命令行参数来控制数据是否首先被序列化。

我能想到的第三种方法是使用 Catch - Generators 的尚未完全就绪的功能:

TEST_CASE("...") {
  using Catch::Generators;
  int iteration(GENERATE(values(0, 1)));
  const bool doSave(iteration == 0);
  const bool doLoad(iteration == 1);
  Repository repository;
  Data data;
  if (doLoad) {
    REQUIRE(repository.load(data));
  } else {
    // fill up data
  }

  REQUIRE(..data..test..);

  if (doSave) {
    REQUIRE(repository.save(data));
  }
}

这种方法的优点是您可以看到流程和测试运行两次(对于两个值),但主要缺点是生成器与 SECTION 和 BDD 样式的功能不兼容。

于 2015-07-09T20:08:20.640 回答