如何使用UnitTest ++从测试中访问私有类字段?

时间:2010-01-18 11:08:10

标签: c++ unit-testing unittest++

使用UnitTest++对单元测试进行编码时,我遇到了麻烦。我想知道如何以干净的方式访问私有成员类字段(或者任何方式......)

到目前为止,我有一个解决方案来使用从被测试类派生的类夹具访问受保护成员。以下代码显示了这个想法:

struct MyFixture : ClassUnderTest { };

TEST_FIXTURE(MyFixture, OneTest)
{
    do_something();
    CHECK(protected_field == true);
}

尽管如此,我认为这不是很干净,因为在某些配置中可能会出现与继承有关的问题,无论如何,只有受保护的成员才能被访问和测试。

我尝试将测试类声明为朋友,但由于这些是由UnitTest ++以某种特殊方式创建的,我还没有成功完成。

有没有人知道如何让测试类成为被测试类的朋友?

是否有其他方式以更简单或不同的方式解决此问题?

提前谢谢大家。

6 个答案:

答案 0 :(得分:13)

有一个非常丑陋但令人惊讶的有用黑客,我通常用于单元测试:

#define private public
#define protected public

#include "class_to_be_tested.h"

// and here, all class's methods and fields are public :P

请勿将其用于除单元测试之外的任何其他内容!

此外,此方法有一些限制 - 首先,并非所有私有都以private为前缀。其次,一个流行的编译器将访问说明符分解为链接器符号。

另一种,也不是那么好的方法是通过铸造。您创建的结构具有相同的字段,但都是公共的,并将其强制转换为指向您的私有结构的指针。然而,这有缺点,类需要完全匹配:

class my_class
{
private:
   char name[40];
   char grade;
   int age;
public:
   //
}

struct my_class_hack
{
public:
   char name[40];
   char grade;
   int age;

}

struct hack_it* my_class_hacked = (my_class_hack*)ptr;

...如果编译器使用你的代码,你会得到令人讨厌的惊喜,所以永远不要将它用于生产代码。

答案 1 :(得分:4)

这是几年前激烈辩论的主题,但普遍接受的结果是你应该只测试你的类的外部可见行为,以便访问其内部数据和行为不是必需的。

虽然这可能最初听起来不太有用,但您可以将要测试的类的私有部分提取到外部行为 您要测试的行为的新类中。然后,您可以以正常方式测试这些类,并且您将改善整体设计。

答案 2 :(得分:4)

单元测试就是通过公共接口测试对象。可能很难的事实是,为什么编写可测试的代码有时被称为 art 。不是每个人都可以立即编写可测试的代码,这就是为什么人们首先发明了编写测试的XP方法。听起来不切实际,在现实中有效。

但是,如果您绝对需要来测试私有函数,请按以下的顺序列出一系列方法:

  1. 私人会员变量将通过公共设置者和获取者访问。

  2. 我建议您在名称空间中使私有成员函数成为非静态非成员函数,例如detailsinternal。不要在头文件中声明它,只需在定义类函数的同一文件中定义它。在单元测试项目的myClass_internal.h头文件中添加其声明并进行测试。所涉及的困难在很大程度上取决于您的架构的复杂性。

  3. 让您的测试类继承自您的可测试类。这并不涉及更改代码,但可能需要使用多重继承,这在某些地方甚至被禁止。

  4. 让您的考试成为您可测试班级的朋友。难度取决于您使用的测试框架。比方说,我使用的是gtest,这很难:)

  5. 如果其他一切都失败了,重新定义公共和私有的黑客应该是你的绝对最后度假胜地。 虽然我宁愿考虑将设计更改为更可测试的设计。

答案 3 :(得分:4)

我也会选择#define Hack,

但也放置一个#define类结构来公开隐式私有类数据。

我必须不同意德米特里:

1。)这会将接口添加到我的生产代码中仅用于测试,并且会违反我的封装。我不希望客户有权访问我的私人数据

2。)再次如1.)中所示 - >好主意,如果那些接口真的只是为了测试而公开

3。)仅在访问受到保护时才有效,这在某种程度上也会影响封装

4。)也意味着修改我的生产代码只是为了测试,甚至在生产代码之间创建一个耦合到我的测试代码!!!

5.。)从你的观点来看,这是正确的,我宁愿拥有丑陋的测试代码而不是丑陋的生产代码:)

答案 4 :(得分:1)

虽然我同意所有人都说“不要”,但有时你正在一个大型项目中工作,你无法自由地对被测试的班级进行所有更改你想要的。对于那些情况,我更喜欢朋友声明公共/私人重新定义hackery。

我想出了如何为UnitTest++做到这一点 这是一个带有“dealInternal”受保护/私有方法的“Deck”类的示例,您希望在“Internals”测试中使用该方法。

    //------------- Deck.h -------------
    namespace SuiteDeck { class TestInternals; }

    class Deck {
        // etc...
        private:
        friend class SuiteDeck::TestInternals;
        bool dealInternal();
    };

    //------------ TestDeck.cpp ----------
    #include "UnitTest++.h"
    #include "Deck.h"

    SUITE(Deck) {
        TEST(Internals) {
            Deck d;
            CHECK(d.dealInternal() == true); // or whatever
        }
    }

答案 5 :(得分:0)

最好避免测试私人物品。为什么要测试private_field?当private_field设置为无效值时会出现什么错误?是否可以测试这种错误的行为,而不是在错误的值上断言?

其他选项包括

  • 在编译代码进行单元测试时,使用预处理器将其公开

  • 将私有字段和相关逻辑提取到一个新的类中,它将是公共的,并使ClassUnderTest依赖于这个新类。