【问题标题】:FRIEND_TEST in Google Test - possible circular dependency?Google 测试中的 FRIEND_TEST - 可能的循环依赖?
【发布时间】:2012-10-21 16:28:21
【问题描述】:

我试图弄清楚 FRIEND_TEST 在 Google 测试中的工作原理。 https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#testing-private-code

我正在查看以下项目,并尝试在我的代码中实现它:

// foo.h
#include "gtest/gtest_prod.h"

// Defines FRIEND_TEST.
class Foo {
  ...
 private:
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  int Bar(void* x);
};

// foo_test.cc
...
TEST(FooTest, BarReturnsZeroOnNull) {
  Foo foo;
  EXPECT_EQ(0, foo.Bar(NULL));
  // Uses Foo's private member Bar().
}

在上面的代码中,我看不到的部分是 foo_test.cc 必须包含 foo.h,才能访问 Foo 和 Bar()。 [也许它对谷歌的工作方式不同?在我的代码中,我必须包含它]

这会导致循环依赖...

我错过了什么吗?

编辑: 代码示例:(修复后重新编辑 - 解决方案是将测试文件从 *.h 更改为 *.cpp):

项目 ppppp - 文件 myfile.h:

class INeedToBeTested
{
public:
  extern friend class blah_WantToTestThis_Test;
  INeedToBeTested();
  INeedToBeTested(INeedToBeTested* item);
  INeedToBeTested(OtherClass* thing, const char* filename);
  ~INeedToBeTested();
  bool Testable();
  std::string MoreTestable();

private:
  int WantToTestThis();
};

项目 ppppp_gtest,文件 myFile_gtest.cpp:

#pragma once
#include "gtest/gtest.h"
#include "myfile.h" //property sheet adds include locations
#include "otherclass.h"

  class blah: public ::testing::Test{
  // declarations, SetUp, TearDown to initialize otherclass thing, std::string filename
  }
  TEST_F(blah, WantToTestThis)
      {
        INeedToBeTested item(thing, filename.c_str());
        item.WantToTestThis();   // inaccessible when this content is in header file
      }

在我努力让它工作的过程中,我还尝试创建一个包装类(这也只在 cpp 中有效,而不是在 header 中);虽然它需要将 private 更改为 protected,但它不需要在每个新测试的测试代码中添加额外的声明:

// option: create wrapper (change private to protected first) 
  class INeedToBeTestedWrapper:public INeedToBeTested 
      {
      public:
         INeedToBeTestedWrapper(OtherClass* thing, std::string filename):
            INeedToBeTested(OtherClass* thing, filename.c_str());
      public:
         using INeedToBeTested::WantToTestThis;
      };

      TEST_F(blah, WantToTestThis)
      {
        INeedToBeTestedWrapper item(thing, filename);
        item.WantToTestThis();   
      }

【问题讨论】:

    标签: c++ unit-testing circular-dependency googletest private-members


    【解决方案1】:

    这里应该没有问题。

    FRIEND_TEST 在这种情况下只是定义

    friend class FooTest_BarReturnsZeroOnNull_Test;
    

    这是使用TEST 宏最终定义的类。无需链接 gtest 或您的任何测试代码到foo library/exe。你只需要像你所做的那样#include "gtest/gtest_prod.h"

    在 foo_test.cc 中,您需要 #include "foo.h",因为它使用的是 Foo 对象的实际实例。您还需要将foo 库链接到测试可执行文件,或者如果foo 不是库,则需要在foo 源中进行编译。

    总而言之,foo 不需要任何测试代码,除了微小的 gtest_prod.h 标头,但测试需要链接到 foo 代码。

    【讨论】:

    • 我无法让它工作 - 我尝试不包括 gtest/gtest_prod.h,而是写实际的“朋友类...”(它似乎也更清楚,它给了我一个更好地理解 gtest 的实际工作原理)。问题可能是命名空间问题 - 生产代码位于匿名命名空间中的事实,在一个单独的项目中 - 如果我实际上包含测试命名空间(请参阅codeproject.com/Articles/484817/…),我收到一个错误,关于测试命名空间是无效。
    • @Mihaela 你的意思是 foo.h 中的类声明在匿名命名空间中吗?如果您将命名空间布局的示例添加到问题中,它可能会有所帮助。正如 codeproject 文章指出的那样,FRIEND_TEST 宏不能很好地处理命名空间,但如果您乐于放弃宏并正常将测试类声明为朋友,那么命名空间问题应该更容易处理。
    • 我添加了代码...有 2 个实现版本。一个添加朋友类,另一个我什至放弃了这个概念,将“私有”的可见性更改为“受保护”,并尝试创建一个包装类,正如 Google 测试文档中的常见问题解答所建议的那样。 (当然,如果我用“extern”添加朋友,我会删除“命名空间 - 但我收到链接错误)
    • @Mihaela 是的 - 您需要将测试夹具(TEST_F(blah, WantToTestThis) 位)移到匿名命名空间之外。它不存在于该编译单元的范围之外,因此它无法访问INeedToBeTested 的私有成员,因为INeedToBeTested 无法“看到”它以使其成为朋友。如果您愿意,测试类可以保留在匿名命名空间中。然后,如果您将friend class blah_WantToTestThis_Test; 添加到INeedToBeTested,您就可以开始了。
    • @Mihaela 差不多了 :-) 从头文件 myFile_gtest.h 中删除 TEST_F 声明 Google 的 TEST_F 宏实际上是在声明类 blah_WantToTestThis_Test,所以即使你没有实现任何在标题中的TEST_F 代码中,您要声明该类两次。 (实际上,您可能会删除整个头文件,除非其他一些 cpp 文件需要访问您的类 blah。)然后将 TEST_F 主体移到 myFile_gtest.cpp 中的匿名命名空间之外,这样它就可以成为朋友INeedToBeTested.
    猜你喜欢
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2023-04-05
    相关资源
    最近更新 更多