代码之家  ›  专栏  ›  技术社区  ›  David

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

  •  13
  • David  · 技术社区  · 15 年前

    当我使用 UnitTest++ . 我想知道怎么进入 私有成员类字段 以一种干净的方式(或者任何方式…)

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

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

    不过,我认为这并不是很干净,因为在某些配置中可能会出现与继承相关的问题,而且,无论如何,只需要受保护的成员就可以被访问和测试。

    我试图将测试类声明为 朋友 但是,由于这些都是由UnitTest++以某种特殊的方式创建的,所以我还没有设法做到这一点。

    有人知道如何使测试类成为测试类的朋友吗?

    有没有其他更简单或不同的方法来解决这个问题?

    提前谢谢大家。

    6 回复  |  直到 13 年前
        1
  •  4
  •   Dmitry    15 年前

    单元测试就是通过公共接口测试对象。这可能很难,这就是为什么写作 可测试的 代码有时被称为 艺术 . 不是每个人都能马上编写可测试代码,这就是为什么人们发明了XP方法首先编写测试。听起来不切实际,实际可行。

    但是,如果你 绝对需要 为了测试私有函数,下面是我根据自己的喜好考虑的方法列表:

    1. 私有成员变量将通过公共setter和getter访问。

    2. 我建议让你成为私人会员 非静态非成员函数 在可调用的命名空间中,例如 details internal . 不要在头文件中声明它,只需在定义类函数的同一个文件中定义它。将其声明添加到 myClass_internal.h 单元测试项目中的头文件并测试它。所涉及的困难很大程度上取决于您的体系结构的复杂性。

    3. 使测试类从可测试类继承。这不需要对代码进行太多的更改,但可能需要使用多重继承,在某些地方甚至是禁止的。

    4. 让你的测试成为你可测试类的朋友。难度取决于您使用的测试框架。说,用 gtest 我用的,很难:)

    5. 重新定义公共和私人的黑客应该是你的 绝对最后 如果一切都失败了,就去度假。 尽管我宁愿把设计改成更具测试性的设计。

        2
  •  13
  •   Kornel Kisielewicz    15 年前

    有一个 真正地 我通常在单元测试中使用的丑陋但非常有用的黑客:

    #define private public
    #define protected public
    
    #include "class_to_be_tested.h"
    
    // and here, all class's methods and fields are public :P
    

    不要将它用于单元测试以外的任何事情!

    而且,这种方法也有一些限制——首先,不是所有private都有前缀 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;
    

    …但是,如果编译器处理您的代码,您可能会遇到令人不快的意外,因此不要将其用于生产代码。

        3
  •  4
  •   GraemeF    15 年前

    这是几年前热议的话题,但普遍接受的结果是你应该只测试 外部可见行为 所以不需要访问它的内部数据和行为。

    虽然这在最初听起来可能没有帮助,但是您可以将类中要测试的私有部分提取到其外部行为的新类中。 你想测试的行为。然后您可以用普通的方法测试这些类,并且您将改进总体设计。

        4
  •  4
  •   TheBigW    15 年前

    我也会去定义黑客,

    但也要放置一个define class struct以使隐式私有类数据也公开。

    我一定不同意德米特里的观点:

    1.)这会将接口添加到我的生产代码中,只是为了测试,并且会违反我的封装。我不希望客户端访问我的私人数据

    2.)同样,如1.)所示。-好主意,如果这些接口实际上只公开用于测试

    3.)只有在访问受到保护的情况下才有效,这在某种程度上也会影响封装。

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

    5.)从你的角度看,这是正确的,我宁愿有丑陋的测试代码,也不愿有丑陋的生产代码:)

        5
  •  1
  •   Emile Snyder    13 年前

    当我同意每个人说“不要 那就是,“有时候你在一个大型项目中工作,在这个项目中,你没有自由去对测试中的类进行你想要的所有更改。对于这些情况,我更喜欢朋友声明而不是公开/私人的重新定义黑客。

    我知道怎么做了 UnitTest++ 下面是一个带有“dealInternal”保护/私有方法的“deck”类的示例,您希望从“内部”测试中使用该方法。

        //------------- 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
            }
        }
    
        6
  •  0
  •   philant    15 年前

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

    其他选项包括

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

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

    推荐文章