软件测试工具Parasoft C/C++test如何通过桩函数实现多次调用返回不同值

在嵌入式系统中,函数往往依赖于外部设备状态或其他模块的返回结果,这使得测试的复杂性显著增加。在实际测试过程中,经常会遇到一个函数多次调用另一个依赖函数,并且需要根据不同的调用顺序返回不同结果的情况。Parasoft C/C++test 作为一款专业的自动化测试工具能够通过桩函数实现多次调用返回不同值,从而完成对复杂逻辑的充分测试。

情况说明

在很多情况下,对一些函数进行单元测试时,该函数需要调用其他函数进行运算,则cpptest会对其被调用的函数进行打桩。但有些情况下,一个函数中多次调用另一个函数,并且需要被调用函数给出不同返回值,程序才可以继续运行。

在cpptest自动化生成的测试用例及桩函数使用中,测试用例调用桩函数的过程是封装的,所以当一个测试用例被设计完成后,它的调用桩的对象是固定的,而一个被打桩函数如果存在多个返回值情况,被测函数根据被打桩函数返回值做一些其他动作时会无法对进行准确测试。例如:

lang-js 复制代码
int funcA();
int funcB()
{
     funcA();
     return funcA();
}

代码中funcB两次调用funcA,而假设funcA是一种设备状态信号返回,当进行测试时,一个测试用例需要两次调用funcA,且2次funcA的返回值不同。

简单的自动化单元测试并无法做到这一点,需要更多的人为介入。

处理方法

本文就简单说明了针对这种情况的处理方法。示例源码:

lang-js 复制代码
int funcA();
int funcB()
{
     funcA();
     return funcA();
}

函数B两次调用函数A,A可能为某些设备状态返回值等,需要在特定状态下函数B做特定的事,比如,第一次调用时A返回1,第二次调用时需要A返回2。

测试用例

lang-js 复制代码
void TestSuite_hhh_c_1e0b7b6_test_funcB_test()
{
    /* Pre-condition initialization */
    {
        /* Tested function call */
        int _return  = funcB();
        /* Post-condition check */
        CPPTEST_ASSERT_INTEGER_EQUAL(2, ( _return ) );
    }
}

可根据实际情况采用自动生成测试用例或根据测试用例向导自行添加。本例中为了方便观察,直接使返回值为2 桩函数**:**

lang-js 复制代码
EXTERN_C_LINKAGE int funcA () ;
EXTERN_C_LINKAGE int CppTest_Stub_funcA (void)
{
    static int i=0;
    i++;
    if(i%2==1){
        return 1;
    }
    else
    return 2;
}</span></span>

此处需要注意,应采用自定义用户桩,并对其进行一部分修改。如上述代码。
对静态变量I进行循环自增,以此来表明调用次数,第一次调用时i经过自增结果为1,1%2结果为1,则funcA返回1,第二次调用时,i经过2次自增值为2,2%2结果为0,则funcA返回2。主要是用i%2这种判定余数的方法来给不同调用次数返回不同值。

验证结果

根据代码情况,在执行函数B测试用例时,第一次调用函数A返回1,第二次调用函数A返回2,则在函数B的测试用例执行之后,正确返回值为2,于是在其中进行断言。下图为测试结果:

测试用例执行成功,证明断言正确。

C++test API

除此以外,C++test还提供了多种API接口来控制桩函数的执行和返回结果。

lang-js 复制代码
* Available C++test API functions (see C++test Users Guide for details):
 *     void CppTest_Assert(bool test, const char * message)
 *     void CppTest_Break()
 *     const char* CppTest_GetCurrentTestCaseName()
 *     const char* CppTest_GetCurrentTestSuiteName()
 *     bool CppTest_IsCurrentTestCase(const char* testCaseName)
 */

比如最后一个可以用来判断当前执行的测试用例是否是某个具体的测试用例,来控制在不同的测试用例中桩函数返回不同的值。比如下面的代码:

lang-js 复制代码
void foo()
{
    if (goo() == 1) {
        //code
    } else {
        //code
    }  
}

为了达到100%的覆盖率,可以创建两个foo()函数的测试用例,然后创建一个替代goo()函数的桩函数来实现:

lang-js 复制代码
int ::CppTest_Stub_goo()
{
    if (CppTest_IsCurrentTestCase("TestCase1")) {
        return 1;
    } else {
        return 0;
    }
}

在C++test实现的截图如下:

这样当执行的测试用例是第一个"test_foo_1"的时候则返回1,否则返回0

当单独执行第一个测试用例的时候,得到的覆盖率如下图:

当单独执行第二测试用例的时候,得到的覆盖率如下图:

当两个测试用例一起执行的覆盖率截图如下所示:

通过灵活运用桩函数的动态控制能力,开发人员能够有效应对单元测试中多次调用同一依赖函数并需要不同返回值的复杂场景,显著提升测试覆盖率和代码可靠性。Parasoft C/C++test还提供了一整套完整的测试解决方案,包括静态代码分析、运行时错误检测以及持续集成支持,帮助团队在开发早期及时发现和修复缺陷,降低项目风险,全面提升软件产品质量和开发效率。

相关推荐
JosieBook5 小时前
【SpringBoot】32 核心功能 - 单元测试 - JUnit5 单元测试中的嵌套测试与参数化测试详解
spring boot·单元测试·log4j
奔跑吧邓邓子2 天前
【C语言实战(79)】深入C语言单元测试:基于CUnit框架的实战指南
c语言·单元测试·实战·cunit
安冬的码畜日常2 天前
【JUnit实战3_31】第十九章:基于 JUnit 5 + Hibernate + Spring 的数据库单元测试
spring·单元测试·jdbc·hibernate·orm·junit5
安冬的码畜日常3 天前
【JUnit实战3_29】第十八章:REST API 接口测试(上)——RESTful 风格的后端 API 的搭建
测试工具·单元测试·restful·rest api·junit 5
安冬的码畜日常3 天前
【JUnit实战3_30】第十八章:REST API 接口测试(下)—— REST API 接口的 MockMvc + JUnit 5 测试实战
测试工具·junit·单元测试·restful·rest api·junit5
慧都小项3 天前
Parasoft C/C++test如何使用桩函数替代MFC窗口类顺利执行单元测试
单元测试·parasoft·桩函数·mfc窗口类
慧都小项4 天前
Parasoft C/C++test中Trace32调试器的配置与单元测试执行
单元测试·parasoft·trace32调试器
JosieBook5 天前
【SpringBoot】31 核心功能 - 单元测试 - JUnit5 单元测试中的断言机制——验证你的代码是否按预期执行了
spring boot·单元测试·log4j
l1t5 天前
编译SQLite 3.51源码并体验新功能
单元测试·sqlite·duckdb