重复测试,插入额外动作的好方法?

时间:2015-05-05 14:02:51

标签: catch-unit-test

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

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

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

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

1 个答案:

答案 0 :(得分: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样式的功能不兼容。