如何在通过autotools构建的项目中使用Google Test?

时间:2016-03-14 21:56:15

标签: c++ unit-testing automated-tests autotools googletest

似乎有一些答案是那种,有点理智,但我不知道如何执行。我还没有找到一个全面的答案。

第一个问题

Google Test不应该是已安装的库,它应该与项目一起构建。 (参见FAQ。)据我所知,这意味着Google Test库是我单元测试的依赖项,应该在我第一次在项目中运行“make check”时构建。这应该在某个目录中构建Google Test库。我不知道该怎么做。它提到了一些被弃用的autotools脚本,我不确定他们在谈论什么或如何正确地指出我的构建。

第二个问题

假设构建成功,我如何编写使用我的本地编译版Google Test运行测试的测试?我假设我在test目录中放了一堆Makefile.am命令。但他们是什么?什么是使用Google Test的单元测试的一个例子?

3 个答案:

答案 0 :(得分:22)

我解决了这个问题让我满意!我现在完全继续前进。这基本上是要求教程。有许多决定必须在逻辑上进行,以便Google Test与autotools很好地吻合。所以我提前为长篇答案道歉,但所有细节都应该在那里。

第一个问题

为了理解答案,这个问题需要稍微改写一下。我们正在将Google Test编译为我们的测试代码将链接到的库。该库将不会安装。我们想问的问题是,“我们如何配置autotools将Google Test编译为我们的测试代码可以链接的库?”

为此,我们需要下载Google Test并将其放入我们的项目中。我有Github,所以我通过在项目的根路径中添加一个子模块来做到这一点:

git submodule add git@github.com:google/googletest.git
git submodule init
git submodule update

这会将googletest下载到我的项目根目录中:

/:
    Makefile.am
    configure.ac
    src/:
        (files for my project)
    tests/:
        (test files)
    googletest/:
        googletest/:
            include/:
                (headers, etc., to be included)
                gtest/:
                    gtest.h
            m4/:
                (directory for m4 scripts and things)
            src/:
                (source files for Google Test)

我需要根据instructions进行编译。我只想在运行make check时构建Google Test库,因此我将使用check_LTLIBRARIES。我将以下内容添加到/ tests中的测试Makefile.am:

check_LTLIBRARIES = libgtest.la
libgtest_la_SOURCES = ../googletest/googletest/src/gtest-all.cc
libgtest_la_CPPFLAGS = -I$(top_srcdir)/googletest/googletest/include -I$(top_srcdir)/googletest/googletest
libgtest_la_LDFLAGS = -pthread

这需要在configure.ac中启用subdir-objects。这是通过将其添加到AM_INIT_AUTOMAKE行来实现的。我还需要在AC_CONFIG_FILES中包含makefile。我们也想使用libtool,因为我们正在编译库文件(我将在稍后解释为什么以及如何工作)。要使用libtool,我们添加AM_PROG_AR,LT_INIT。我们希望autoreconf将m4宏安装到/ m4,然后我们希望automake找到它们,所以我们需要AC_CONFIG_MACRO_DIRS。我的configure.ac已更新行:

AM_INIT_AUTOMAKE([-Wall -Werror subdir-objects])
...
AM_PROG_AR
LT_INIT
AC_CONFIG_MACRO_DIRS([m4])
...
AC_CONFIG_FILES([Makefile
                 src/Makefile
                 tests/Makefile
                 ])

我还需要在/Makefile.am的/ m4宏目录中包含子目录和指向宏的行:

ACLOCAL_AMFLAGS = -I m4

SUBDIRS = src tests

这样做了什么? Libtool已启用AM_PROG_AR和LT_INIT。 check_LTLIBRARIES意味着我们将使用libtool创建一个名为libgtest.la的便捷库。启用subdir-objects后,它将内置到/ tests目录中,但不会安装。这意味着,每当我们想要更新测试时,我们就不必重新编译Google Test库libgtest.la。这将节省测试时间并帮助我们更快地迭代。然后,我们将在稍后更新它们时编译我们的单元测试。该库只会在运行make check时进行编译,如果我们想做的只是makemake install,则不会编译它来节省时间。

第二个问题

现在,第二个问题需要改进:你如何(a)创建一个链接到Google Test库并因此使用它们的测试(b)?问题是相互交织的,所以我们马上回答。

创建测试只需将以下代码放入位于/tests/gtest.cpp的gtest.cpp文件中:

#include "gtest/gtest.h" // we will add the path to C preprocessor later

TEST(CategoryTest, SpecificTest)
{
    ASSERT_EQ(0, 0);
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);

    return RUN_ALL_TESTS();
}

这只运行简单测试0 = 0。要为您的库创建测试,您需要阅读primer。您会注意到我们不需要标题(尚未)。我们链接到文件“gtest / gtest.h”,因此我们需要确保告诉automake包含一个包含gtest / gtest.h的目录。

接下来,我们需要告诉automake我们要构建测试并运行它。测试将构建为我们不想安装的可执行文件。然后automake将运行该可执行文件。它将报告该可执行文件是否表示测试通过或失败。

Automake通过在makefile中查找变量check_PROGRAMS来做到这一点。这些是它将编译的程序,但它不一定会运行它们。所以我们添加到/tests/Makefile.am:

check_PROGRAMS = gtest

gtest_SOURCES = gtest.cpp

gtest_LDADD = libgtest.la

gtest_LDFLAGS = -pthread

gtest_CPPFLAGS = -I$(top_srcdir)/googletest/googletest/include -I$(top_srcdir)/googletest/googletest -pthread

gtest_SOURCES找到/tests/gtest.cpp文件并编译它。 gtest_LDADD链接libgtest.la,它将被编译到/ tests目录中。 Google希望我们使用gtest_LDFLAGS行来启用pthread。最后,我们需要包含将找到标题“gtest / gtest.h”的位置,即gtest_CPPFLAGS行。 Google还希望我们添加/ googletest / googletest位置,并添加

状态: Google Test库libgtest.la将使用make编译到目录/ tests中,但不会安装。二进制gtest只能用make check编译,但不会安装。

接下来我们要告诉automake实际运行已编译的二进制gtest并报告错误。这是通过在/tests/Makefile.am中添加一行来实现的:

TESTS = gtest

最终的/tests/Makefile.am看起来像这样:

check_LTLIBRARIES = libgtest.la
libgtest_la_SOURCES = ../googletest/googletest/src/gtest-all.cc
libgtest_la_CPPFLAGS = -I$(top_srcdir)/googletest/googletest/include -I$(top_srcdir)/googletest/googletest -pthread

check_PROGRAMS = gtest demo

gtest_SOURCES = gtest.cpp ../src/fields.cpp

gtest_LDADD = libgtest.la

gtest_LDFLAGS = -pthread

gtest_CPPFLAGS = -I$(top_srcdir)/googletest/googletest/include -I$(top_srcdir)/src

demo_SOURCES = demo.cpp ../src/fields.cpp

demo_CPPFLAGS = -I$(top_srcdir)/src

TESTS = gtest

现在,来自/和autoreconf -fiv make check(注意任何错误,并希望修复它们),你应该得到一个运行的测试:

build(dev)$ make check
Making check in tests
/Applications/Xcode.app/Contents/Developer/usr/bin/make  gtest
make[2]: `gtest' is up to date.
/Applications/Xcode.app/Contents/Developer/usr/bin/make  check-TESTS
PASS: gtest
============================================================================
Testsuite summary for IonMotion 0.0.1
============================================================================
# TOTAL: 1
# PASS:  1
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================

答案 1 :(得分:2)

以下是单元测试项目的Makefile.am示例(项目名称:TestProject)。这取决于GTEST和GMOCK:

<强> Makefile.am

#######################################
# The list of executables we are building seperated by spaces
# the 'bin_' indicates that these build products will be installed
# in the $(bindir) directory. For example /usr/bin
#bin_PROGRAMS=exampleProgram

# Because a.out is only a sample program we don't want it to be installed.
# The 'noinst_' prefix indicates that the following targets are not to be
# installed.
noinst_PROGRAMS=utTestProject

#######################################
# Build information for each executable. The variable name is derived
# by use the name of the executable with each non alpha-numeric character is
# replaced by '_'. So a.out becomes a_out and the appropriate suffex added.
# '_SOURCES' for example.

# Sources for the a.out 
utTestProject_SOURCES= \
    utTestProject.cpp

# Library dependencies
utTestProject_LDADD = \
    $(top_srcdir)/../TestProject/build/${host}/libTestProject/.libs/libTestProject.a \
    ../$(PATH_TO_GTEST)/lib/libgtest.a \
    ../$(PATH_TO_GMOCK)/lib/libgmock.a 

# Compiler options for a.out
utTestProject_CPPFLAGS = \
    -std=c++11 \
    -I../$(PATH_TO_GTEST)/include \
    -I../$(PATH_TO_GMOCK)/include \
    -I$(top_srcdir)/include \
    -I$(top_srcdir)/..

TESTS = utTestProject

TESTS_ENVIRONMENT = export UT_FOLDER_PATH=$(top_srcdir)/utTestProject; \
                    export GTEST_OUTPUT="xml";

编译gtest:

# Useful vars
SourceVersionedArchiveFolderName="gtest-1.7.0"

#
# Make it
#
pushd .
cd ./${SourceVersionedArchiveFolderName}/make

make gtest.a
if [ $? != 0 ]; then
    echo "$0: Make failed"
    exit 1
fi

popd

答案 2 :(得分:0)

值得注意的是,Googletest不再正式维护其Autotools集成:

  

在开始使用CMake之前,我们一直在提供手动维护的版本   Visual Studio,Xcode和Autotools的项目/脚本。当我们   继续为他们提供方便,他们并不积极   保持更多。我们强烈建议您遵循   上述各节中的说明,以将Google Test与您的   现有的构建系统。

https://github.com/google/googletest/tree/master/googletest#legacy-build-scripts

现在建议使用CMake构建Googletest。

  

可以将GoogleTest的源代码提供给主版本   做了几种不同的方式:

     
      
  • 手动下载GoogleTest源代码并将其放置在已知的位置   位置。这是最不灵活的方法,可以做得更多   难以与持续集成系统等配合使用。
  •   
  • 嵌入   GoogleTest源代码作为主项目源代码中的直接副本   树。这通常是最简单的方法,但也是最困难的方法   不断更新。一些组织可能不允许这种方法。
  •   
  • 添加   GoogleTest作为git子模块或等效的子模块。这可能并不总是   可能或适当的。例如,Git子模块有自己的   一整套优点和缺点。
  •   
  • 使用CMake将GoogleTest下载为   构建的配置步骤的一部分。这只是一点   复杂,但没有其他方法的局限性。
  •   

https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project