首页 > 解决方案 > Google 测试发现在 mac OS X 上添加并运行了我所有的测试两次

问题描述

我会尽量保持简短,但要简洁。

我一直在移植我公司使用的谷歌测试框架(和一套测试),从 Windows 到 mac os。除了在 MAC 上构建/运行测试时出于某种原因,我几乎所有的东西都可以正常工作……谷歌测试将我定义的每个测试都包含了两次。

在 MAC 上,我的 Makefile 输出“main_test”,如果我使用 --gtest_list_tests 选项来快速显示问题,您可以看到我的简化测试列表都重复了第二次。

$ ./main_test --gtest_list_tests
BEGINNING Google Test!
sman_drift_test.
  slow_forward
  medium_back
  slow_forward
  medium_back
motor_self_test/motor_test.
  self_test/0  # GetParam() = "rev"
  self_test/1  # GetParam() = "fwd"
  self_test/0  # GetParam() = "rev"
  self_test/1  # GetParam() = "fwd"

在 Windows 上的 VS 中编译的完全相同的源文件会生成我的“unit_test_d.exe”文件,如果我从“cmd”shell 运行相同的 --gtest_list_tests 选项,我会得到:

>unit_test_d.exe --gtest_list_tests
BEGINNING Google Test!
sman_drift_test.
  slow_forward
  medium_back
motor_self_test/motor_test.
  self_test/0  # GetParam() = "rev"
  self_test/1  # GetParam() = "fwd"

在我的servo_drift_test.cpp 文件中只有一份这些测试的副本,在motor_self_test.cpp 文件中也是如此。

TEST_F(sman_drift_test, slow_forward) 
{
     // Do my test stuff...
}

TEST_F(sman_drift_test, medium_back) 
{
     // Do my test stuff...
}

我已经搞砸了几天了......我已经消除了很多可能的选择。基本上包括我所有的公司代码。

我最初遵循此 Web 链接上的 MAC 设置说明:http: //hack.limbicmedia.ca/installing-google-test/

注意:我应该注意......在按照这些说明进行操作时,我确实更改了目录并使用了我们树中已经存在的“gtest”文件(版本列在底部),所以我可能会弄乱文件放置,或者可能是重新编译我们已经下载的源代码并将这些目录放置在正确位置时的构建选项。希望不会。我们的原始库是使用 VS 2015 for Windows 编译的...我使用上面链接中列出的 cmake 和安装步骤构建了相同的源文件。我在 /usr/local/inc 和 lib 中确实有 gtest.h 和 libgtest.a,所以包含路径的东西应该很好(?)。

并按照它的指示运行示例代码。同样......我看到了同样的问题......注意:我注释掉了“TEST(FactorialTest,零)”案例,只是为了验证注释掉1个测试......确实消除了两个实例。它确实做到了。但是你可以看到......“负”和“正”都被添加了两次,以及所有 3 个“IsPrime()”测试。

$ ./sample1 --gtest_list_tests
Running main() from gtest_main.cc
FactorialTest.
  Negative
  Positive
  Negative
  Positive
IsPrimeTest.
  Negative
  Trivial
  Positive
  Negative
  Trivial
  Positive

同样,实际运行测试会导致运行重复的测试。样本中有 6 个测试用例,FactorialTest 中有 3 个,IsPrimeTest 中有 3 个。您可以看到它正在构建/运行每组两次...每组 6 个,总共 12 个:

$ ./sample1
Running main() from gtest_main.cc
[==========] Running 12 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 6 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 6 tests from FactorialTest (0 ms total)

[----------] 6 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 6 tests from IsPrimeTest (0 ms total)

[----------] Global test environment tear-down
[==========] 12 tests from 2 test cases ran. (0 ms total)
[  PASSED  ] 12 tests.

我已经对这个问题进行了大量研究,并且不认为这是与我自己的库或目标文件的链接问题。

问题当然可能与 Google Test 的某些构建选项以及由它创建/安装的库(-lgtest)有关。有可能它被链接了两次(?),或者在谷歌测试中是否有某种定义或参数设置说“运行我所有的测试两次”?注意:这个问题不是“./sample_test --gtest_repeat=2”选项。这重复了我重复的测试两次,因此它们每次运行 4 次。

最后,这可能是一个潜在的提示......以及我是如何首先进入这个兔子洞的......当我使用我的完整代码堆栈而不是“样本”时......我连接到的地方一个串行端口并维护我的串行句柄结构......正如你所看到的......一旦我使用地址(0x6d009f0)和文件描述符FD [3]设置我的指针......我丢失了它......或者更有可能有一个附加一个定义(为NULL)......与测试的“重复”实例。

此外,奇怪的是它去哪里 NULL ......以及它回来的地方。流程如下所示:

Start Google Test
 - Do Init.  IE: Establish and init Serial port (init, open, config port)
    - Pointer GOOD Addr(0x6d009f0) FD[3]
    - Get Device Serial Number (Works)
 - Begin servo_drift_test
    - Do "SetUpTestCase()" Init Code
       - Set Device Mode to 2, required for this "set" of tests.
       - Pointer GOOD  Addr(0x6d009f0) FD[3]
    - Run First Test Case *** Now I presume this is the "duplicate" case
       - Pointer LOST Addr(0)... NULL (Not initialized)
       - TEST instance ONE FAILS
    - Run Second Test Case *** This appears to have the matching memory space as the original init and setup code!!!
       - Runs a SUCCESSFUL "get_params" command.
       - Pointer GOOD  Addr(0x6d009f0) FD[3]
       - TEST instance TWO PASSED
    - Servo Drift Test "TearDownTestCase()"
       - Nothing To Do Here
 - Complete Test Summary

如您所见,它运行了 2 个测试用例实例……尽管在这个非常简单的精简示例中只有 1 个“测试”。我尽力清理它,但仍然显示调试打印。:)

我发现测试用例的“SetUp”只运行一次......并且运行良好。但是同一个测试的两个实例,显然一个不在同一个内存空间。这可能是 Google Test 如何添加“测试”与“测试集”的症状。但我猜这是对整体问题的暗示。

  $ ./main_test port=/dev/cu.usbserial-FTFMEXDK
unit_test version: 6.00.00
  Set Port String[64]: /dev/cu.usbserial-FTFMEXDK <---
  Global Port String: /dev/cu.usbserial-FTFMEXDK <---
using serial port /dev/cu.usbserial-FTFMEXDK
SUCCESS - GET_PORT_BY_NAME
             PORT - Struct Addr port2print[6d009f0]
                  - Name: /dev/cu.usbserial-FTFMEXDK
                  - Baudrate: -1
                  - Bits: -1
                  - Parity: -1
                  - Stopbits: -1
                  - FD[-1]

SUCCESS - SP_OPEN in Mode[3]
             PORT - Struct Addr port2print[6d009f0]
                  - Name: /dev/cu.usbserial-FTFMEXDK
                  - Baudrate: 9600
                  - Bits: 8
                  - Parity: -1
                  - Stopbits: 1
                  - FD[3]

SUCCESS - SET_BAUDRATE 460800
             PORT - Struct Addr port2print[6d009f0]
                  - Name: /dev/cu.usbserial-FTFMEXDK
                  - Baudrate: 460800
                  - Bits: 8
                  - Parity: 0
                  - Stopbits: 1
                  - FD[3]



  WRITE
    - [29]: sys_config get_smart_sn
  PROXY RECEIVE START
 TOK[19] EXP[19] ==>  0x00000000  1 0 E 2 0 1 1 7 0 6 2 7 0 0 1 4 8 R  
Target ALIVE, unit serial no: '10E20117062700148R'


BEGINNING Google Test!
Note: Google Test filter = *.slow_forward
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from sman_drift_test
             PORT - Struct Addr port2print[6d009f0]
                  - FD[3]
  WRITE
    - [24]: sys_config set_mode  2 
  PROXY RECEIVE START
 TOK[1] EXP[1] ==>  0x00000000   

[ RUN      ] sman_drift_test.slow_forward
             PORT - Struct Addr port2print[0]
                  - NULL PORT Structure!!! 

          ERROR - comm port initialization failed
servo_drift_test.cpp:485: Failure
Failed
UNABLE TO COMMUNICATE WITH DEVICE


[  FAILED  ] sman_drift_test.slow_forward (15013 ms)
[ RUN      ] sman_drift_test.slow_forward
              - PreTestFlags[0x7]
             PORT - Struct Addr port2print[6d009f0]
                  - FD[3]

  WRITE
    - [17]: sman get_params 
  PROXY RECEIVE START
 TOK[13] EXP[13] ==>  0x00000000  1 0 0 -1471 1 0 0 0 0 0 1 75000  

[       OK ] sman_drift_test.slow_forward (29114 ms)
[----------] 2 tests from sman_drift_test (44127 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (45607 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] sman_drift_test.slow_forward

但是,如果有人想看的话,这是我的 Makefile(我正在为我的非 Windows 串行连接代码使用“libserialport”……理想情况下,这将建立在许多平台上)。据我所知,Makefile 运行和构建都很好。我正在使用它来构建,一切正常。注意:我确实为这个例子更改了“rpclibstuff”的名称,因为实际名称是我们产品的一部分......所以出于安全原因我将其隐藏了。:) 因此,如果存在与“rpclibstuff”相关的语法错误,则可能只是在此示例中。:)一个

$ cat Makefile 
# Include directories for rpc .h files
RPCINC=../../../Common/rpc/inc/
RPCSRC=../../../Common/rpc/src/

# Include directory for the "system_mode.h" include
TAINC=../../../Tensioner/application/inc/

# Direcroty path for libserialport
LSDIR=../libserialport/

all: main_test

main_test: rpclibstuff.a 
    g++ -std=c++11 -stdlib=libc++ main.cpp servo_drift_test.cpp motor_test.cpp -lgtest -lpthread -o main_test -I $(RPCINC) -I $(LSDIR) -L. -lrpclibstuff -lserialport

rpclibstuff.a: rpc_util.o rpc_proxy.o rpc_proxy_util.o rpc_dispatch_util.o
    ar rcs librpclibstuff.a rpc_dispatch_util.o rpc_proxy.o rpc_proxy_util.o rpc_util.o


# gcc "-c" option compiles source files without linking.
rpc_util.o: $(RPCSRC)rpc_util.c
    gcc -c $(RPCSRC)rpc_util.c -o rpc_util.o -I $(RPCINC) -I $(TAINC)

rpc_proxy.o: $(RPCSRC)rpc_proxy.c
    gcc -c $(RPCSRC)rpc_proxy.c -o rpc_proxy.o -I $(RPCINC)

rpc_proxy_util.o: $(RPCSRC)rpc_proxy_util.c
    gcc -c $(RPCSRC)rpc_proxy_util.c -o rpc_proxy_util.o -I $(RPCINC)

rpc_dispatch_util.o: $(RPCSRC)rpc_dispatch_util.c
    gcc -c $(RPCSRC)rpc_dispatch_util.c -o rpc_dispatch_util.o -I $(RPCINC)

clean:
    rm *.o *.a main_test

附加背景:我的公司给了我一段代码,这是一个谷歌测试框架(v1.7.0)和一整套通过串行连接到我们产品的测试套件。几年来没有人看过这个,而且它都是基于 Windows 的。构建基于 Windows 的“unit_test_d.exe”文件输出。我能够显着构建和扩展它,并且该项目是在 VS 2015 中构建的......我能够将它转发并在 VS 2017 v15.6.7 中打开/构建项目

然后我被赋予了将整个项目移植到 mac 的任务,这样我们就可以与我们已经为我们的产品提供的 BLE(蓝牙)引擎进行交互。同样,从 mac 终端继续测试,而不需要 windows 虚拟机或 windows 盒子。我已经成功地移植了代码,因此它仍然可以在两个平台上运行(很多 #ifdef _WIN32 或 #ifdef APPLE),我现在可以在 Windows 上的 VS 以及带有终端 shell 的 mac os x 上构建项目。

如果其中任何一个措辞不正确,请致歉。:)

对此问题的任何帮助将不胜感激。抱歉这篇文章的长度,但我想在第一次提供尽可能多的具体信息!:) 谢谢!!!

标签: c++macosgoogletest

解决方案


我最初认为这可能是我的编译器 (gcc/g++) 的问题,因为当我在 XCODE 中构建时,问题就消失了。

然而,XCODE 所做的只是将输出文件“sample1”放在不同的位置。事实证明,我运行文件的实际位置很重要。我可以从我的 test/src/ 目录运行它,并且所有测试都是重复的,当我从 /use/local/bin/ (XCODE 放置它的地方)运行它时,它运行良好。此外......将(完全相同的)文件从一个位置移动到另一个位置,并执行它会导致工作或不工作......取决于我运行文件的位置。

运行我的测试文件时,我能够使用 Activity Monitor (mac) 查看“打开的文件/端口”......并将其缩小到从一个位置运行时包含的神秘库,但不是从另一个位置运行。

该库是 /usr/lib/libprelaod.dylib

我在“dgagent”文件夹中找到了这个库(并复制到 /usr/lib ......两者都有相同的时间/日期戳),我认为它是 Digital Guardian 产品的一部分......可能我的公司已经安装在我的机器上。

我不知道这个库中有什么,也不知道为什么它让 Google Test 可执行文件运行所有测试两次。我也不知道为什么将可执行文件移动到不同的位置会影响测试的运行次数,以及为什么在编译/构建时没有这样做。

但事实证明,我不在乎。我现在将输出的测试文件放在 /usr/local/bin/ 并从那里运行它,它工作得很好。

无论如何,我想发布一个更新,以防其他人看到类似的问题......或者只是想回答一下为什么会发生这种情况。:)

谢谢,J


推荐阅读