我们应该为单元测试修改功能签名吗?

时间:2019-05-30 06:43:35

标签: c++ unit-testing testing

假设我们有一个函数add()如下:

void add(int a, int b) {
    int sum=a+b;
    cout<<sum;
    sendSumToStorage(sum);
}

此简单功能可添加输入值,将总和打印到控制台,并将其发送到某个外部存储(例如文件)。理想情况下,这就是我们在应用程序中想要它的方式(意味着,我们不希望它返回任何内容)。

出于单元测试的目的,如果我们修改函数签名以使其返回sum,它是否有效(从设计角度而言)?然后我们可以进行如下测试:

bool checkAdd() {
    int res=add(3, 4);
    if(res==7) return true;
    else return false;
}

更好的是,这(返回一个值)是我们可以对其进行单元测试的唯一方法吗?是否有某种 valid 方法可以在不更改函数签名的情况下对add()函数进行单元测试?

3 个答案:

答案 0 :(得分:3)

像您示例中的函数那样的函数被认为是非常糟糕的做法。

我为什么要这样说?

嗯,您有一种名为 add 的方法,该方法将两个数字相加 AND 会调用其他名称。基本上,您的方法不执行任何操作,而是执行两项操作,这违反了“单一责任原则”。

这使测试变得更加困难,因为您不能单独测试add方法。

因此,您可以将其分为两个具有好名字的方法,以反映它们的作用并分别进行测试。

如果您不希望方法之间的状态出现问题,则必须在有意义的地方开始返回结果。

答案 1 :(得分:0)

忽略此示例的设计意图不佳的事实。

在这种情况下,当您要检查某些内部行为而不是API时,您应该尝试使用一些测试库,例如gtest和gmock。 它可以让您描述比功能结果更复杂的期望。

例如,您可以设置期望使用EXPECT_CALL宏在代码执行期间调用某些方法。

更多详细信息在这里: https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md

回答您的问题,出于测试目的而修改测试代码的任何部分始终是一种不良做法。在这种情况下,您将不再测试生产代码。正如之前建议的那样,最好将功能拆分为较小的部分并进行隔离测试。

答案 2 :(得分:0)

更改代码设计以提高可测试性非常普遍,通常被认为是一种好习惯。显然,并非所有此类更改都一定是真正的改进-有时存在更好的解决方案。

在您的情况下,代码难以测试,因为它结合了计算(加法)以及与依赖组件(输出和存储数据)的交互。在您的情况下(如Andrei所指出的),该功能还违反了SRP,但是即使没有违反SRP的情况,混合计算和交互操作通常也会使测试更加困难。

我知道,除了打印并将其写入存储器外,您还应该更改函数以使其返回计算值。这将允许您测试函数的计算部分。但是,该功能将仅部分测试。并且,该功能的目的将进一步模糊。

相反,如果您将函数拆分为一个函数进行计算,一个函数进行交互,则可以使用单元测试对第一个函数进行彻底测试,而对另一个函数使用集成测试。同样,此方法的有效性与代码是否违反SRP没有关系。