与第三方单元测试框架集成

概述

Coco测试引擎支持直接集成流行的单元测试框架,包括CPPUnitGoogle TestQt Test

这意味着自动发现的测试行成为这些框架下常规测试套件的一部分;当运行测试套件时,结果将出现在常规统计信息中。

与驱动器方法相比,并不总是可以提供命令行参数来自定义第三方单元测试框架的执行。因此,我们有一个运行配置文件,该文件由Coco测试引擎读取。与驱动器方法的另一个不同之处在于,第三方集成无法处理测试函数中的崩溃,因为没有可以重新启动可执行文件的单独驱动程序程序。

源代码

要集成Coco测试引擎,需要在使用的测试框架下编写一个普通源文件,但需要一些额外的宏来控制测试执行。宏是用以下形式的语句导入的:

#include "CocoTestEngine_<framework>.h"

其中<框架>可以是cppunitgoogletestqtest之一。有关示例,请参阅此处

这些头文件提供了以下宏

COCOTEST_BEGIN

COCOTEST_BEGIN( <testname> ):声明测试循环的开始。此宏以以下形式使用:

COCOTEST_BEGIN( test )
{
    <fetch statements>
    <function calls>
    <check statements>
}
COCOTEST_END()

其中的大括号(即COCOTEST块)之间(也称为代码)成为包含对COCOTEST_FETCHCOCOTEST_CHECK调用和任意代码的while循环体。

<test declaration>表示需要在第三方框架中在测试用例开始时编写的代码,<test end>是测试结束的代码。

此宏定义了一个名为 <testname> 的测试。这是用来查找该测试的配置和数据文件的名称。(请注意,测试框架还可能在 <test declaration> 部分定义一个测试名称,这两个名称可能不同。)

在测试和学习模式下,COCOTEST 块会重复执行,对于数据文件中的每一行都执行一次。在发现模式下,对于遗传算法产生的每个数据行都会运行此代码。在测试模式下,如果某行失败,测试将失败。

从单元测试框架的角度来看,我们的代码似乎是一个单一的数据驱动测试,尽管它可能在多行数据上运行。然而,当我们打开 CoverageBrowser 的执行报告时,我们会看到每一行作为一个独立的执行。

COCOTEST_END

COCOTEST_END():出现在 COCOTEST 块的闭括号后面。

COCOTEST_FETCH

COCOTEST_FETCH( <type>, <identifier> ):声明一个变量并获取其内容。

此宏使用 <identifier> 名称声明一个指定类型的变量,并将其赋予一个值。有关可能类型的列表,请参阅此处。在测试和学习模式下,值从数据文件中某行的 "<identifier>" 名称的 input 字段中获取。在发现模式下,它由 遗传算法 生成。

所有 COCOTEST_FETCH 语句都必须位于 COCOTEST 块的开始部分。

COCOTEST_CHECK

COCOTEST_CHECK( <identifier> ):保存或验证一个变量。

<identifier> 必须是已经声明的变量的名称。有关它可以具有的类型列表,请参阅此处

在测试模式下,变量的值与数据文件中当前行的 "<identifier>" 名称的 output 字段值进行比较。如果它们不同,测试将失败(并终止)。

在学习模式下,<identifier> 的当前值会覆盖数据文件中的值。在发现模式下,将生成一个新的行,其中输出值 "<identifier>" 是变量的当前值。在发现过程结束时,新行可能被写入到数据文件中,或者在此期间被丢弃。

所有 COCOTEST_CHECK 语句都必须位于 COCOTEST 块的末尾。

COCOTEST_SET_DATADIR

COCOTEST_SET_DATADIR( <directory> ):此宏设置配置目录。如果 <directory> 是相对路径,它将相对于 unittest 程序的当前工作目录进行解释。

编译

对于 unittest 程序的编译,只需添加一个包含路径,以便编译器找到适当的文件 CocoTestEngine_framework.h 并启用代码覆盖率——所有需要的 CocoTestEngine_framework.h 语言都在头文件中。

  • 在默认安装的 Linux 下,带有 CocoTestEngine.h 的目录是 /opt/SquishCoco/include
  • 在 Windows 下,它在 %SQUISHCOCO%\include,其中 %SQUISHCOCO% 是 Coco 安装目录的路径环境变量,安装程序会自动设置。

然后必须扩展编译器的包含路径,以便搜索这些目录。

单元测试程序和包含被测试函数的库的源文件必须使用代码覆盖率进行编译。与常规代码覆盖率不同,需要额外的选项。在简单的情况下,选项可能是:

--cs-on --cs-test-case-generation --cs-exclude-file-wildcard=* --cs-include-file-wildcard=*/librarydir/*

它们的目的在于:

  • --cs-on 用于启用代码覆盖率。
  • --cs-test-case-generation 用于测试用例生成支持。
  • --cs-mcdc 或 {–cs-mcc}(可选)用于生成更多可以被搜索算法使用的仪器化点。
  • --cs-exclude-file-wildcard=* --cs-include-file-wildcard=*/librarydir/* 仅生成库代码(以及源文件本身)的代码覆盖率。这样,搜索算法可以更清楚地看到哪些更改导致了更高的代码覆盖率。

    而不是 librarydir,可以使用存储库代码所在的目录名称。如果需要,可以使用多个 --cs-include-file-wildcard 标志。

注意:您的单元测试的代码覆盖率仪器化仅在运行发现模式时是必需的。测试和学习模式不需要仪器化二进制文件。有关详细信息,请参阅运行模式

运行测试

为了运行(或发现)一个测试,它必须有权访问数据目录。该目录可以通过COCOTEST_SET_DATADIR或其他方式设置;请参阅此处

该目录必须始终包含一个配置文件,其中指定了所有用于COCOTEST_FETCHCOCOTEST_CHECK的变量。默认情况下,unittest程序处于测试模式;然后必须也存在一个数据文件

如果需要学习模式或发现模式,这可以通过运行配置文件进行指定。如果指定发现模式,则数据文件是可选的,在发现运行中必要时将创建。(如果有数据文件,则其值将用作发现的起点。)

集成到受支持的测试框架中

以下列出Coco测试引擎与受支持的第三方框架集成的示例。它们都展示了框架中的一个单个测试实例,以及需要使用(可选的)COCOTEST_SET_DATADIR语句做什么。

CPPUnit

#include "CocoTestEngine_cppunit.h"

#include "cppunit/TestAssert.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>

class TestSuite : public CppUnit::TestFixture
{
    CPPUNIT_TEST_SUITE( TestSuite );
    CPPUNIT_TEST( testName );
    CPPUNIT_TEST_SUITE_END();

protected:
    void testName( void )
    {
        COCOTEST_BEGIN( test_header_cppunit )
        {
            <fetch statements>
            <function calls>
            <check statements>
        }
        COCOTEST_END()
    }
};

CPPUNIT_TEST_SUITE_REGISTRATION( TestSuite );

int main( int argc, char *argv[] )
{
    COCOTEST_SET_DATADIR( <directory> );  // optional

    CppUnit::TextUi::TestRunner runner;
    CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
    runner.addTest( registry.makeTest() );
    bool wasSuccessful = runner.run( "", false );
    return !wasSuccessful;
}

Google Test

#include <gtest/gtest.h>
#include "CocoTestEngine_gtest.h"

static void SetUpTestSuite()
{
    COCOTEST_SET_DATADIR( <directory> );  // optional
}

TEST( testSuite, testName )
{
    COCOTEST_BEGIN( test_header_googletest )
    {
        <fetch statements>
        <function calls>
        <check statements>
    }
    COCOTEST_END()
}

Qt Test

#include <QTest>
#include "CocoTestEngine_qtest.h"

class TestSuite : public QObject
{
    Q_OBJECT
private slots:

    void initTestCase()
    {
        COCOTEST_SET_DATADIR( <directory> );  // optional
    }

    void testName()
    {
        COCOTEST_BEGIN( TestSuite )
        {
            <fetch statements>
            <function calls>
            <check statements>
        }
        COCOTEST_END()
    }
};

QTEST_MAIN( TestSuite )
#include "TestSuite.moc"

Coco v7.2.0©2024 The Qt Company Ltd.
Qt及其相关标志是芬兰以及/或世界上其他国家的The Qt Company Ltd.的商标。所有其他商标均为其各自所有者的财产。