【问题标题】:Specify constructor arguments for a Google test Fixture为 Google 测试夹具指定构造函数参数
【发布时间】:2016-11-07 12:31:12
【问题描述】:

通过 Google 测试,我想指定一个用于不同测试用例的测试夹具。 夹具应分配和释放类TheClass及其数据管理类TheClassData的对象,其中数据管理类需要数据文件的名称。
对于不同的测试,文件名应该不同。

我定义了以下 Fixture:

class TheClassTest : public ::testing::Test {
 protected:
  TheClassTest(std::string filename) : datafile(filename) {}
  virtual ~TheClassTest() {}
  virtual void SetUp() {
    data = new TheClassData(datafile);
    tc = new TheClass(data);
  }
  virtual void TearDown() {
    delete tc;
    delete data;
  }

  std::string datafile;
  TheClassData* data;
  TheClass* tc;
};

现在,不同的测试应该使用具有不同文件名的夹具。 将其想象为设置测试环境。

问题:如何从测试中指定文件名,即如何调用夹具的非默认构造函数?

我发现了诸如 ::testing::TestWithParam<T>TEST_P 之类的东西,这并没有帮助,因为我不想用不同的值运行一个测试,而是用一个夹具运行不同的测试。

【问题讨论】:

  • 所以你想自己运行那个夹具? google test 默认测试运行器无法实例化带参数的fixture。
  • 我想使用夹具运行测试(可能是TEST_F)。所以答案是,这不可能吗?谢谢。
  • 我认为TestWithParam<T>TEST_P 正是您所需要的。查找Advanced Docs 如何在实践中使用它们。您始终可以在测试用例中实例化被测实例(我假设它是TheClass)。

标签: c++ unit-testing constructor googletest


【解决方案1】:

根据另一位用户的建议,您无法实现您想要的 通过使用非默认构造函数实例化夹具。然而, 还有其他方法。只需重载SetUp 函数并 在测试中显式调用该版本:

class TheClassTest : public ::testing::Test {
protected:
    TheClassTest() {}
    virtual ~TheClassTest() {}
    void SetUp(const std::string &filename) {
        data = new TheClassData(filename);
        tc = new TheClass(data);
    }
    virtual void TearDown() {
        delete tc;
        delete data;
    }

    TheClassData* data;
    TheClass* tc;
};

现在在测试中只需使用这个重载来设置文件名:

TEST_F(TheClassTest, MyTestCaseName)
{
    SetUp("my_filename_for_this_test_case");

    ...
}

无参数TearDown会自动清理 测试完成。

【讨论】:

  • 太棒了。非常感谢!
  • SetUp 方法仍将被 gtest 调用,导致两次调用 SetUp ...因此在这种情况下存在内存泄漏,因为 TearDown 仅删除最后的分配。我会将 SetUp 重命名为其他名称,以便 gtest 不会调用它。
  • 对不起,我错了。由于您的 Setup 带有一个参数,因此 gtest 不会调用它。我会将 SetUp 重命名为其他名称,因为它可能与 gtest 调用的 SetUp() 混淆。
【解决方案2】:

使用当前类作为您的灯具的基类:

class TheClassTestBase : public ::testing::Test {
 protected:
  TheClassTestBase(std::string filename) : datafile(filename) {}
  ...
 };

对于每个特定的文件名 - 使用派生的夹具:

class TheClassTestForFooTxt : public TheClassTestBase {
protected:
    TheClassTestForFooTxt() : TheClassTestBase ("foo.txt") {}
};

但是,对于每组参数,这都是额外的步骤 - 因此您可以尝试使用模板或宏来轻松完成它。喜欢:

template <typename ClassTestTag>
struct ClassTestParams
{
    static std::string filename;
};

template<typename  ClassTestTag>
class TheClassTest : public TheClassTestBase {
protected:
    TheClassTest() : TheClassTestBase (ClassTestParams<ClassTestTag>::filename) {}
};

然后 - 对于每组参数 - 这样做:

class FooTxtTag {};
template <> std::string ClassTestParams<FooTxtTag>::value = "foo.txt";
using TheClassTestForFooTxt = TheClassTest<FooTxtTag>;
TEST_F(TheClassTestForFooTxt, xxxx) {}

但是 - 在您的具体情况下 - 我也会尝试 GoogleTest:type-parameterized-tests

【讨论】:

  • 谢谢。我认为这对于我的问题规模来说有点过分了。
  • 文档链接已损坏
【解决方案3】:

解决这个问题的另一种好方法是扩展您的夹具,并在扩展类中提供一个新的默认构造函数,该构造函数使用您需要的参数调用旧构造函数。例如:

struct MySpecializedTestFixture : public GenericTestFixture
{
  MySpecializedTestFixture() : GenericTestFixture("a thing", "another thing") {}
};

TEST_F(MySpecializedTestFixture, FancyTest)
{
  // Use the thing environment and make some assertions.
}

【讨论】:

    【解决方案4】:

    如果您按照建议的here 重载SetUp 方法,并且要确保记住使用重载的SetUp,则可以在TearDown 方法中使用断言。

    class my_fixture : public ::testing::Test
    {
    protected:
        bool SETUP_HIT_FLAG = false;
    
        void SetUp(double parameter)
        {
            ...
            SETUP_HIT_FLAG = true;
        }
    
        void TearDown() override
        {
            assert(SETUP_HIT_FLAG && "You forgot to call SetUp with your parameter!");
        }
    };
    

    【讨论】:

      【解决方案5】:

      对于这种特殊情况,我觉得完全摆脱测试夹具要容易得多。 SetUp 函数可以替换为使用所需文件名实例化类的辅助函数。这允许使用TEST 而不是TEST_PTEST_F。现在每个测试用例都是一个独立的测试,它使用辅助函数或直接在测试用例的主体中创建自己的测试类实例。

      例如:

      using namespace testing;
      TEST(FooClassTest, testCase1)
      {
          FooClass fooInstance("File_name_for_testCase1.txt");
          /* The test case body*/
          delete fooInstance;
      }
      

      【讨论】:

      • OP 询问有关使用测试夹具的问题。这个例子没有展示如何重用datafiledatatcdelete fooInstance 怎么了?
      猜你喜欢
      • 2013-02-11
      • 1970-01-01
      • 1970-01-01
      • 2019-11-07
      • 1970-01-01
      • 2023-03-28
      • 2019-04-20
      • 2018-03-01
      • 2011-10-27
      相关资源
      最近更新 更多