如何对通过 autotools 构建的项目使用 Google 测试?

How can I use Google Test with my project that builds via autotools?

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

第一个问题

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

第二题

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

这是单元测试项目(项目名称:TestProject)的示例 Makefile.am。这取决于 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 "[=11=]: Make failed"
    exit 1
fi

popd

我已经满意地解决了问题!我现在将继续前进。这基本上是在寻求教程。有很多必须做出的决定,希望是合乎逻辑的,以便 Google 测试与自动工具很好地吻合。所以我提前为冗长的回答道歉,但所有的细节都应该在那里。

第一个问题

为了理解答案,问题需要稍微改写一下。我们正在编译 Google 测试作为我们的测试代码将 link 到的库。不会安装该库。我们想问的问题是

"How do we configure autotools to compile Google Test as a library which our test code can link against?"

为此,我们需要下载 Google 测试并将其放入我们的项目中。我使用 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 进行编译。我只想在 运行ning make check 上构建 Google 测试库,所以我将使用 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 测试库 libgtest.la。这将节省测试时间并帮助我们更快地迭代。然后,我们将希望稍后在更新它们时针对它编译我们的单元测试。该库将仅在 运行 宁 make check 时编译,如果我们只想 makemake install.

,则不编译它可以节省时间

第二题

现在,第二个问题需要细化:您如何 (a) 创建测试 (b) linked 到 Google 测试库并因此使用它们?问题比较复杂,一一解答。

创建测试只是将以下代码放入位于 /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。您会注意到我们(目前)不需要 header。我们正在 link 访问文件“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 links 反对 libgtest.la 将被编译到 /tests 目录中。 Google 希望我们使用 gtest_LDFLAGS 行来启用 pthreads。最后,我们需要包含 header "gtest/gtest.h" 所在的位置,即 gtest_CPPFLAGS 行。 Google 还希望我们包括 /googletest/googletest 位置,并包括

情况: Google 测试库 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 你应该得到一个测试 运行s:

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
============================================================================

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

Before settling on CMake, we have been providing hand-maintained build projects/scripts for Visual Studio, Xcode, and Autotools. While we continue to provide them for convenience, they are not actively maintained any more. We highly recommend that you follow the instructions in the above sections to integrate Google Test with your existing build system.

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

现在建议使用 CMake 构建 Googletest。

Making GoogleTest's source code available to the main build can be done a few different ways:

  • Download the GoogleTest source code manually and place it at a known location. This is the least flexible approach and can make it more difficult to use with continuous integration systems, etc.
  • Embed the GoogleTest source code as a direct copy in the main project's source tree. This is often the simplest approach, but is also the hardest to keep up to date. Some organizations may not permit this method.
  • Add GoogleTest as a git submodule or equivalent. This may not always be possible or appropriate. Git submodules, for example, have their own set of advantages and drawbacks.
  • Use CMake to download GoogleTest as part of the build's configure step. This is just a little more complex, but doesn't have the limitations of the other methods.

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