4

我是测试新手,我需要关于最佳测试策略(及其应用)的建议。这是我的问题:

我有一个程序可以读取文件并自动提取其结构。我想测试进行这种“智能”提取的方法。最初,我可以使用一些文件来检查该方法是否进行了正确的提取。然后我想使用这些文件和(正确的)提取结果进行测试。由于提取结果已经过验证,它们应该(并且必须)用于进一步的测试。

所以,我有类似的东西:对于“这个特定的文件”,我期望“这个结果”。

问题:

  1. 很容易获得测试的输入文件。我会将它们存储在特定目录中。结果呢?它们影响存储文件结构的对象的内容。在这种情况下,我可能还需要将此对象保存在文件中。有了序列化,恐怕随着对象结构的改变,之前保存的对象就很难复用了。

  2. 随着越来越多的结果,我可能有数百个文件和结果,测试将花费大量时间。我希望测试时间不会是一个大问题。

我需要测试,因为我在方法中使用的“提取算法”会经常改变。为了拥有完美的提取算法,我无法应对所有可能性。所以,我的解决方案是构建一个在十几个文件中工作的初始算法,每次我发现特定文件的算法失败时,我都会更改算法以解决该文件的问题。应测试此更改以使以前的文件和结果仍然有效。

对测试策略有什么建议吗?

4

3 回答 3

1

对于测试,您需要一个可以注入输入测试数据的地方和一个可以观察某些行为或输出的地方。

在输入方面:文件真的是注入输入测试数据的唯一可能性吗?如果是,则该应用程序没有良好的可测试设计。带有文件的测试很难维护。在输出端:应用程序似乎没有提供观察行为或输出的可能性。这指向不可测试的设计。

即使您找到一种方法来观察我们的输出行为,也只会对所有提取算法进行端到端测试。这样的端到端测试是脆弱的并且是维护的噩梦。原因是一个不好的可测试设计。

如果没有良好的可测试设计,您将无法实施良好的测试策略。您将需要更改应用程序的设计。另一方面,您可能会争辩说您不想在没有任何测试的情况下更改设计。这似乎是一个先有鸡还是先有蛋的问题。

如何摆脱这样的局面?测试和重构策略的组合可能会有所帮助。在高层次上,这可能像这样工作:

  1. 构建一些有代表性的端到端测试。因此,甚至使用序列化技巧。这只是为了验证您的程序是否像开始重构之前一样工作。它们充当迁移测试

  2. 重构你的程序。给它注射和观察的地方。这样的地方被称为接缝

  3. 结果,您将拥有可测试的块,您可以将其放入 测试工具中。

  4. 你重构并在代码中加入新的接缝,以测试更小的块,直到你有单元测试到位。理想情况下,您会将所有算法封装到一个类家族中,这些类都经过单元测试。

听起来很辛苦?不,实际上它比听起来更难。将应用程序重构为可测试的设计需要大量经验。幸运的是,有人为此写了一本书:Michael Feather 的 'Working Effectively with Legacy Code'

如果您真的非常想为现有应用程序实施一个好的测试策略,那么请阅读那本书。如果你想知道下次你能做的更好,读那本书。如果您认为单元测试可能是避免不可测试设计的关键,那么现在就开始学习单元测试。互联网上有很多关于单元测试的资源和书籍。

于 2013-01-19T18:50:44.250 回答
0

如果我了解问题所在,您需要保留测试结果以供以后检查或额外测试。它通常不愿意在编写测试代码上投入太多时间,但在这种情况下,我认为没有立即可用的替代方案。

我的建议是尽可能多地解耦所涉及的部分:算法、持久层(序列化/反序列化)、其产品和验证码。

以后的算法实现也有可能共享相同的接口,例如:

interface IMyAlgorithm {
  AbstractOutput DoSomething (InputData);
}

class ConcreteOutput : AbstractOutput {
  // Output for version XXX of your algorithm
}

class XXXAlgorithm {
  ConcreteOutput DoSomething (InputData inputData)
    // Version XXX of you alogorithm
  }
}

interface IPersistenceManager {
  Serialize(AbstractOutput output, string filename);
  AbstractOutput Deserialize(string filename)
}

class XXXPersistenceManager : IPersistenceManager {
  // Handle persistence for XXX hierarchy
}

class XXXTestFixture {
  void BuildObjectWithXXXAlgorithm() {
    IMyAlgorithm XXX = new XXXAlgorithm();
    // run XXX here
    AbstractOutput objXXX = XXX.DoSomething(new InputData());
    IPersistenceManager pmXXX = new XXXPersistenceManager();
    pmXXX.Serialize(objXXX);
  }

  void VerifyThatXXXWorkAsExpected() {
    IPersistenceManager pmXXX = new XXXPersistenceManager();
    AbstractOutput objXXX = pmXXX.Deserialize(path);
    // check object here
  }
}

所以当你需要创建一个新算法时,比如 YYY,你就创建了相应的层次结构。无论如何我不知道细节,这只是一个伪代码草稿,放在这里只是为了强调松散耦合的应用程序组件。

于 2013-01-19T14:21:07.197 回答
0

您可以尝试使用批准测试来验证给定的输入文件是否始终在 memory-object-graph 中生成相同的文件。

为此,您需要将内存中对象图转换为其字符串表示形式的代码(即覆盖 ToString() 或具有 xml-serializer)

Approvaltests 验证生成的字符串是否始终相同。

如果字符串表示更改,您将获得一个 diff-viewer,并要求您验证更改是否仍然正常。如果更改正常,您将将此结果用于以后的验证。

于 2013-01-19T15:41:24.713 回答