3

考虑这样的代码:

class ToBeTested {
public:
  void doForEach() {
    for (vector<Contained>::iterator it = m_contained.begin(); it != m_contained.end(); it++) {
       doOnce(*it);
       doTwice(*it);
       doTwice(*it);
    }
  }
  void doOnce(Contained & c) {
    // do something
  }
  void doTwice(Contained & c) {
    // do something
  }

  // other methods
private:
  vector<Contained> m_contained;
}

我想测试如果我用 3 个值填充向量,我的函数将以正确的顺序和数量调用。例如,我的测试可能如下所示:

tobeTested.AddContained(one);
tobeTested.AddContained(two);
tobeTested.AddContained(three);

BEGIN_PROC_TEST()
SHOULD_BE_CALLED(doOnce, 1)
SHOULD_BE_CALLED(doTwice, 2)
SHOULD_BE_CALLED(doOnce, 1)
SHOULD_BE_CALLED(doTwice, 2)
SHOULD_BE_CALLED(doOnce, 1)
SHOULD_BE_CALLED(doTwice, 2)

tobeTested.doForEach()
END_PROC_TEST()

你建议如何测试这个?有没有办法用 CppUnit 或 GoogleTest 框架来做到这一点?也许其他一些单元测试框架允许执行这样的测试?

我知道如果不从这些函数中调用任何调试函数,这可能是不可能的,但至少可以在某些测试框架中自动完成。我不喜欢扫描跟踪日志并检查它们的正确性。

UPD:我不仅尝试检查对象的状态,还尝试检查执行顺序以避免尽早出现性能问题(通常我想知道我的代码完全按照我的预期执行)。

4

7 回答 7

2

您应该能够使用任何好的模拟框架来验证对协作对象的调用是否按特定顺序完成。

但是,您通常不会测试一个方法对同一类上的其他方法进行一些调用......为什么会这样?

通常,当您测试一个类时,您只关心测试其公开可见的状态。如果您测试其他任何内容,您的测试将阻止您以后进行重构。

我可以提供更多帮助,但我认为您的示例不一致(AddContained 方法的实现在哪里?)。

于 2008-09-17T01:04:13.493 回答
1

您可以查看mockpp

于 2008-09-17T00:58:37.500 回答
1

与其试图弄清楚调用了多少个函数以及以什么顺序调用,不如找到一组输入,如果你以正确的顺序调用事物,它们只能产生预期的输出。

于 2008-09-17T01:22:56.210 回答
1

如果您对性能感兴趣,我建议您编写一个测量性能的测试。

检查当前时间,运行您关心的方法,然后再次检查时间。断言所花费的总时间小于某个值。

检查方法是否按特定顺序调用的问题是您的代码将不得不更改,并且您不想在发生这种情况时更新您的测试。您应该专注于测试实际需求,而不是测试满足该需求的实现细节。

也就是说,如果您真的想测试您的方法是否按特定顺序调用,您需要执行以下操作:

  1. 将他们移到另一个班级,称之为 Collaborator
  2. 将这个其他类的实例添加到 ToBeTested 类
  3. 使用模拟框架将 ToBeTested 上的实例变量设置为 Collborator 类的模拟
  4. 调用被测方法
  5. 使用您的模拟框架来断言在您的模拟上以正确的顺序调用了这些方法。

我不是本地 cpp 演讲者,所以我无法评论您应该使用哪个模拟框架,但我看到其他一些评论者在这方面添加了他们的建议。

于 2008-09-17T02:05:36.497 回答
0

一些模拟框架允许您设置有序的期望,这让您可以准确地说出您期望按特定顺序调用的函数。例如,RhinoMocks for C# 允许这样做。

我不是 C++ 编码员,所以我不知道 C++ 有什么可用的,但这是一种可能允许您尝试执行的工具。

于 2008-09-17T00:56:17.023 回答
0

http://msdn.microsoft.com/en-au/magazine/cc301356.aspx

这是一篇关于上下文绑定对象的好文章。它包含一些非常先进的东西,但如果你不懒惰并且真的想了解这类东西,它会非常有帮助。

最后,您将能够编写如下内容: [CallTracingAttribute()] public class TraceMe : ContextBoundObject {...}

于 2008-09-17T01:13:15.127 回答
0

您可以使用 ACE(或类似的)调试框架,并在您的测试中,将调试对象配置为流式传输到文件。然后你只需要检查文件。

于 2008-09-17T01:23:25.320 回答