13

I'm facing a nuisance when coding my unit tests using UnitTest++. I'm wondering how to access private member class fields in a clean way (or maybe any way...)

By now, I have a solution to access protected members using a class fixture deriving from the class under test. The following code shows the idea:

struct MyFixture : ClassUnderTest { };

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

Nevertheless, I think this is not very clean, because problems relating inheritance could arise in some configurations and, anyway, just protected members can be accessed and tested.

I tried to declare test classes as friends, but as these are created in some special way by UnitTest++, I haven't managed to do it yet.

Does anyone have any idea of how to make test classes friends of the the classes under test?

Is there another way of approaching this problem in an easier or different way?

Thank you all in advance.

4

6 回答 6

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;

...但是,如果编译器使用您的代码,您可能会得到令人讨厌的惊喜,因此切勿将其用于生产代码。

于 2010-01-18T11:12:32.180 回答
6

单元测试就是通过对象的公共接口来测试你的对象。编写可测试的代码有时会被称为艺术,这可能是困难的事实。不是每个人都能立即编写可测试的代码,这就是为什么人们首先发明了 XP 编写测试的方法。听上去不切实际,实事求是。

但是,如果您绝对需要测试私有函数,以下是我会根据自己的偏好考虑的方法列表:

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

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

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

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

  5. 如果其他一切都失败了,重新定义公共和私人的黑客应该是你绝对的最后手段。尽管我宁愿考虑将设计更改为更可测试的设计。

于 2010-01-18T15:46:06.077 回答
4

我也会去#define Hack,

而且还放置了一个#define 类结构来公开隐式私有类数据。

我必须不同意德米特里:

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

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

3.) 仅在访问受到保护时才有效,这在某种程度上也损害了封装

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

5.)从你的角度来看是对的,我宁愿有丑陋的测试代码而不是丑陋的生产代码:)

于 2010-01-18T17:05:56.940 回答
4

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

虽然这最初听起来可能没有帮助,但您可以将要测试的类的私有部分提取到新类中,其外部行为就是您要测试的行为。然后,您可以以正常方式测试这些类,您将改进您的整体设计。

于 2010-01-18T11:12:31.923 回答
1

虽然我同意每个人所说的“不要那样”,但有时您正在一个大型项目中工作,在该项目中您没有自由对被测类进行所有您想要的更改。对于这些情况,我更喜欢朋友声明而不是公共/私人重新定义黑客。

我想出了如何为UnitTest++做到这一点 这是一个“Deck”类的示例,该类具有“dealInternal”受保护/私有方法,您想从“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
        }
    }
于 2011-07-19T18:12:52.533 回答
0

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

其他选项包括

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

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

于 2010-01-18T11:14:29.667 回答