单元测试:进行最小测试是否有效?

时间:2012-09-27 22:06:34

标签: unit-testing mockito

我有一个关于单元测试的基本问题。我在代码中发现了崩溃,我写了一个测试来重现这个bug。然后我修复了错误并确认它通过了测试。我的问题是,如果我采取最好的方法。这是一个简化的例子:

public class ClassC
{
    private int internalFlag;

    void all(Dependency dep1, Dependency dep2, Dependency dep3, Dependency dep4)
    {
        a(dep1);
        b(dep2)
        c(dep3)
        d(dep4)
        e();
        f();
    }

    void e()
    {
        if (some logic based on dep3)
        {
            internalFlag = 2;
        }
    }

    void f()
    {
        if (internalFlag == 2)
        {
            Log("All is well");
        }
        else
        {
            Log("Crash occurs")
        }
    }
}

在上面的例子中,我有一个名为" all"它调用方法a,b,c,d,e,f。现在,我发现了" f"因为" internalVar"不是预期的价值。这个' internalVar"设置在" e",但正如你所看到的那样" e"如果条件为false,则不将internalFalg设置为任何内容。所以bug就在e。

我能够编写测试来隔离bug。然后我修复了bug,发现测试过去了。多数民众赞成,但为了做到这一点,我必须做一些事情:

void testAll()
{
    mockDep1 = mock(dep1);
    mockDep2 = mock(dep2);
    mockDep3 = mock(dep3);
    mockDep4 = mock(dep4);

    all(mockDep1, mockDep2, mockDep3, mockDep4);
}

现在我在这个示例中创建mockDep1..4的部分非常简单,但它实际上是非常费力的代码。我的问题是,它是有效的,只是为了做最小的调用来重现崩溃:

void testCrash()
{
   mockDep3 = mock(dep3);
   c(mockDep3)    
   e()
   f();
}

这将是重现和测试崩溃所需要做的所有事情,除了它不完全是如何在实际方法中调用代码" all",它调用每个方法。它似乎就像上面写testAll包括所有的模拟一遍又一遍,每个bug都有点tedius。但话说回来,那就是实际的方法" all"会工作。那么最好是隔离bug,即使隔离不完全是如何调用完整方法的呢?

1 个答案:

答案 0 :(得分:0)

从您的示例中不清楚哪些方法是公开的,哪些是私有的(或受保护的或包私有的)。如果唯一的公共方法是名为all的公共方法,那么只要有可能,这是您的测试应该调用的方法,除非您正在测试实际上只包含在其中一种方法中的复杂逻辑。

当您选择要编写哪些测试时,您应该专注于此类合同的内容。您的应用程序的其他部分期望此类提供哪些功能?根据功能的基础确定测试方法;不是你碰巧写的方法。

此外,如果Dependency类的唯一目的是支持ClassC的功能,那么你可以考虑编写其SUT是这个ClassC和Dependency的测试(有些人称之为“集成测试”,有些人称之为“单元测试,其中单元由两个类组成“)。

在您的特定情况下,您的类似乎提供了跨越方法运行的功能。因此,请测试功能 - 并测试可能导致功能以不同方式工作的不同方案。不要测试个别方法。特别是,您将在各种情况下调用all方法进行大量测试;其中一些导致错误发生(至少在你修复bug之前),其中一些没有。

最后,为了帮助您考虑测试功能和方案,我认为您应该根据正在执行的功能和方案命名您的测试方法,而不是通过被调用的方法。特别是,我认为testAll(事实上,任何由test组成的名称后跟方法名称)都是测试方法的不良名称。但也许这是另一天要考虑的事情。