【问题标题】:GoogleTest for Android NDK C++ with CMakeGoogleTest for Android NDK C++ with CMake
【发布时间】:2017-09-16 02:58:07
【问题描述】:

如何使用 CMake 在 Android 上为我的本机 C++ 代码设置 GoogleTest? Android NDK 与 googletest 捆绑在一起,但说明仅适用于 Android.mk (here)。如何将 Android.mk gtest 设置移植到我的 CMakeLists.txt?一旦设置完成,是否可以通过 Android Studio 的测试配置运行测试运行器?

【问题讨论】:

    标签: c++ android-ndk cmake googletest


    【解决方案1】:

    我只能回答您的第一个主要问题,但这是一个可行的解决方案。它不是特定于 Android 的;只要您可以运行 CMake 和 CTest,它就可以工作。

    我对 GoogleTest 了解不多,但我记得几个月前有一个非常相似的问题。就我而言,我想将 CMake 与 Boost UnitTestFramework 一起使用。

    我搜索了一下,然后发现a certain tutorial。他们提供的解决方案只是使用正则表达式解析您的测试文件的内容。好处是,它非常可定制,并且允许每个文件进行多个单元测试。我这样做了,而且效果很好。当然,当您添加新的单元测试时,您必须重新运行 CMake。

    就像我说的,我将在下面发布针对 Boost UnitTestFramework 的内容,但最大的区别在于正则表达式和我使用的变量名。如果您不习惯在 CMake 中使用正则表达式(我不习惯),here 是有关字符串操作的官方文档页面。

    这是我最终得到的CMakeLists.txt 文件。我将其用作test/ 目录下的独立CMakeLists.txt 文件。

    # =============================
    # =       ADDING TESTS        =
    # =============================
    
    include(CTest)
    
    find_package(Boost COMPONENTS unit_test_framework REQUIRED)
    include_directories(${Boost_INCLUDE_DIRS})
    
    file(GLOB_RECURSE TEST_SRCS RELATIVE ${TEST_SOURCE_DIR} *.cpp)
    
    set(TEST_EXTRA_LIBS ${Boost_LIBRARIES} ${TEST_MAIN_LIB})
    
    
    # Function which, given a file name and a test name, yields the
    # name of the GoogleTest test case.
    # That way, several different files can have the same test name.
    # Adapt this to GoogleTest.
    function(getTestCase testFileName testName outTestCase)
        string(REGEX MATCH "Test([_a-zA-Z][_a-zA-Z0-9]*)" match ${testFileName})
        string(REGEX REPLACE ".*Test([_a-zA-Z][_a-zA-Z0-9]*).*" "\\1" testCase ${match})
        set(testCase Test${testCase}${testName})
        set(${outTestCase} ${testCase} PARENT_SCOPE)
    endfunction()
    
    
    # Function which adds all tests within a certain test file.
    function(add_all_tests_in testSrc)
        get_filename_component(testFileName ${testSrc} NAME_WE)
    
        add_executable(${testFileName} ${testSrc})
        target_link_libraries(${testFileName} ${TEST_EXTRA_LIBS})
        set_target_properties(${testFileName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
    
        file(READ "${testSrc}" testFileContents)
    
        # You should change this Regex for what you need in your case.
        # Maybe something like:
        # "TEST\\( *([_a-zA-Z][_a-zA-Z0-9]* *, *[_a-zA-Z][_a-zA-Z0-9]*) *\\)"
        string(REGEX MATCHALL "DEF_TEST_CASE\\( *([_a-zA-Z][_a-zA-Z0-9]*) *\\)" unitTests ${testFileContents})
    
        foreach(match ${unitTests})
            # This replace will also probably need some change.
            string(REGEX REPLACE ".*\\( *([_a-zA-Z][_a-zA-Z0-9]*) *\\).*" "\\1" testName ${match})
            getTestCase(${testFileName} ${testName} testCase)
            # Actually add the test.
            # I wanted my CTest test names to be in the form
            # <fileName>.<testName>, but you can use any
            # format you want. Suit yourself.
            # 
            # Also, in order for CMake to run the tests one by one,
            # you have to find how to invoke the test executable.
            # In the case of Boost, the option --run_test=<Boost_Test_Name>
            # runs only the test called <Boost_Test_Name>. There should be
            # an equivalent option for GoogleTest, I'm sure.
            add_test(NAME "${testFileName}.${testName}" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${testFileName} --run_test=${testCase} --catch_system_error=yes)
        endforeach()
    endfunction()
    
    
    
    # Actually add all tests in all test files.
    foreach(testSrc ${TEST_SRCS})
        add_all_tests_in(${testSrc})
    endforeach()
    

    为我工作。在build/ 目录下运行 CMake 后,运行所有测试会产生:

    $ cd test && ctest
    
    Test project /home/anthonyd973/Git/Git_Projects/MySweeper/build/test
          Start  1: TestFieldMaker.makeFromFile
     1/12 Test  #1: TestFieldMaker.makeFromFile ........   Passed    0.03 sec
          Start  2: TestFieldMaker.make
     2/12 Test  #2: TestFieldMaker.make ................   Passed    0.01 sec
          Start  3: TestFieldMaker._computeFieldDims
     3/12 Test  #3: TestFieldMaker._computeFieldDims ...   Passed    0.01 sec
          Start  4: TestFieldMaker._populateField
     4/12 Test  #4: TestFieldMaker._populateField ......   Passed    0.00 sec
          Start  5: TestInputField.InputField
     5/12 Test  #5: TestInputField.InputField ..........   Passed    0.00 sec
          Start  6: TestCell.Cell
     6/12 Test  #6: TestCell.Cell ......................   Passed    0.00 sec
          Start  7: TestCell.initNeighbours
     7/12 Test  #7: TestCell.initNeighbours ............   Passed    0.00 sec
          Start  8: TestCell.updateNeighbours
     8/12 Test  #8: TestCell.updateNeighbours ..........   Passed    0.00 sec
          Start  9: TestCell._mark
     9/12 Test  #9: TestCell._mark .....................   Passed    0.00 sec
          Start 10: TestMySweeper.MySweeper
    10/12 Test #10: TestMySweeper.MySweeper ............   Passed    0.00 sec
          Start 11: TestField.Field
    11/12 Test #11: TestField.Field ....................   Passed    0.01 sec
          Start 12: TestField._initNeighbours
    12/12 Test #12: TestField._initNeighbours ..........   Passed    0.00 sec
    100% tests passed, 0 tests failed out of 12
    Total Test time (real) =   0.10 sec
    

    希望,使用正则表达式不会导致您two problems :)。

    【讨论】:

    • @user740857 这个答案有用吗?如果是,请随时接受它和/或奖励赏金。如果不是,您能否简要解释一下原因,以便其他人有机会为您提供更好的答案?
    • 非常感谢您的见解。我似乎仍然不明白如何从您的信息转到 Android 设置。
    • @user740857 是的,我确实为您提供了一个相当复杂的解决方案。但我认为没有任何简单的方法可以在不编写 CMake 代码的情况下将 GoogleTest 移植到 CMake。
    猜你喜欢
    • 2019-03-20
    • 1970-01-01
    • 2012-04-02
    • 2014-03-30
    • 2018-11-04
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多