单元测试 - 复杂方法应该如何进行单元测试?

时间:2013-03-05 08:20:32

标签: unit-testing complexity-theory

我们假设,我正在测试以下类(〜伪代码):

// (...)
public Result Process(Image image)
{
    Image image2 = PreprocessImage(image);
    PartialResult r1 = Process1(image2);
    PartialResult r2 = Process2(r1);
    Result result = FinalProcessing(r2);

    return result;
}

public Image PreprocessImage(Image image)
{
    Image tmp1 = Resize(image);
    Image tmp2 = Blur(tmp1);
    Image tmp3 = Median(tmp2);
    Image tmp4 = ExtractSpecificAreas(tmp3);

    return tmp4;
}

public Image Median(Image image)
{
     // Actual image median algorithm
}

对于问题更多......有问题,让我们假设,大多数这些方法(例如,Process1,Process2,FinalProcessing,ExtractSpecificAreas)的结果都难以预测 - 例如,有一些启发式/决定性的试图从图像中提取特征的算法:它可以在90%的情况下成功,这是可以接受的。

您将对这些方法中的哪一种进行单元测试?除无效的输入/边界条件外,您如何对这些方法进行单元测试?该方法对于单元测试有意义(或多么复杂)有意义吗?

2 个答案:

答案 0 :(得分:7)

单元测试的一般规则是测试可以测试的最小可能部分。一个好的规则是每个测试都应该使用公共API中的一个方法。

这意味着它应该只执行这种方法而不是其他方法,甚至不是短暂的。因此,如果您要测试foo()并调用bar(),那么您应该模拟bar()而不是测试它。但是,调用内部私有方法baz()也没关系。

如果您的方法调用了数百个内部方法,则需要refactoring

原因是单元测试失败应该指向问题的确切位置。如果您要进行单元测试main(),那么失败只会告诉您项目代码中存在某个错误。如果你进行单元测试,比如String.length()并且测试失败了,你就会知道错误的确切位置。

这也回答了你的问题:你的方法会返回不可预知的结果。模拟它们将允许您始终返回已知的好/坏结果,因此您可以测试正确处理这些结果的方法。

对于不可预测的方法,您必须找到类似的策略。我在这里假设你有一些训练有素的神经网络,例如。因此,测试可能是将一些训练图像传递给方法N次,直到您确信图像在90%的时间内正确排序。

您应该能够将这些方法拆分为可预测和不可预测的部分,然后您可以使用模拟或统计分析进行测试。

两个很棒的模拟框架是MockitoPowerMock

答案 1 :(得分:1)

我认为Aaron Digulla已经指出了最重要的事情:测试最小的碎片并使用模拟物体。

但是,我还要补充一点:您可能还想测试整个应用程序,即小块是否能够很好地协同工作(这将是集成测试而不是单元测试,但无论如何 - 你应该两者兼顾)。为了测试启发式算法,我发现从 easy 任务开始解决它很有用 - 在你的情况下,这将是一种“简单”的图像。当然,这只会给你一个基线,并不能保证它在90%的情况下有效。但是无论如何它在开发过程中都很有用,如果你愿意的话,你可以随时使用更逼真的样本来增强你的(集成)测试套件。