Qt 中是否可以对私有方法进行单元测试(访问)?

发布于 2024-12-04 06:05:14 字数 145 浏览 2 评论 0原文

我正在为我的应用程序编写单元测试,现在我偶然发现了一个应该在其中测试私有方法的类。这可能是特定课程设计不当的结果,但我必须这样做。 Qt 中有没有办法调用私有方法,也许使用 QMetaObject 或类似的东西?

对于单元测试,我使用 QTestLib 框架。

I'm writing unit tests for my app, and now I've stumbled on a class in which I should test private methods. This could be result of poor design of particular class, but I must do it. Is there any way in Qt to call private methods, maybe using QMetaObject or something similar ?

For unit testing I am using QTestLib framework.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

但可醉心 2024-12-11 06:05:14

正确的(读起来烦人的)答案是您不应该测试私有方法,这些是实现细节;-)

OTOH - 您是否考虑过有条件地声明它们受保护/私有,具体取决于您是否正在进行测试,然后进行扩展?我过去曾用它来摆脱类似的困境。

#ifdef TESTING
// or maybe even public!
#define ACCESS protected
#else
#define ACCESS private
#endif

/* your class here */
class Foo {
ACCESS
    int fooeyness;
}

// or better yet, place this in a different file!
#ifdef TESTING
/*
    class which extends the tested class which has public accessors
*/
#endif

The proper (read annoying) answer is that you should not be testing private methods, those are implementation details ;-).

OTOH -- have you thought about conditionally declaring them protected/private depending on whether you are in testing or no and then extending? I've used that to get me out of a similar pinch in the past.

#ifdef TESTING
// or maybe even public!
#define ACCESS protected
#else
#define ACCESS private
#endif

/* your class here */
class Foo {
ACCESS
    int fooeyness;
}

// or better yet, place this in a different file!
#ifdef TESTING
/*
    class which extends the tested class which has public accessors
*/
#endif
红玫瑰 2024-12-11 06:05:14

解决方案 1,快速且简单:使测试类成为公共类的朋友。

class Foo {
   // ...
private:
   friend class FooTest;
};

这样您的 FooTest 类就可以访问公共类的所有成员。然而,这样,每次想要从不同的测试访问私有数据时,都需要修改原始类,并且会泄漏公共 API 中有关测试的信息,并且可能会出现类命名冲突(如果有/怎么办)另一个/ FooTest 类周围?),等等。


解决方案2,又名正确完成:不要将私有方法放在公共类中,而是使用公共方法创建私有类。

class Foo {
    // 
private:
    friend class FooPrivate;
    FooPrivate *d;
};

FooPrivate 在其自己的标头中声明,该标头可能不会安装,或者保留在 include-privates/ 子目录中,或者其他什么 - 即它不会妨碍正常使用。这样公共课就保持干净了。

class FooPrivate {
public:
    // only public stuff in here;
    // and especially this:
    static FooPrivate *get(Foo *f) { return f->d; }
};

然后,测试包含私有标头并调用 FooPrivate::get(fooObj) 来获取私有类实例,然后愉快地使用它。

Solution 1, quick and easy: make the test class(es) a friend of the public one.

class Foo {
   // ...
private:
   friend class FooTest;
};

This way your FooTest class can access all members of the public class. However, this way you need to modify the original class every time you want to access private data from a different test, and you leak information about the tests in the public API, and you possibly open up for class naming conflicts (what if there's /another/ FooTest class around?), and so on.


Solution 2, aka properly done: don't put private methods in the public class, but make a private class with public methods.

class Foo {
    // 
private:
    friend class FooPrivate;
    FooPrivate *d;
};

FooPrivate gets declared in its own header, which may not be installed, or stay in a include-privates/ subdirectory, or whatever -- i.e. it stays out of the way for normal usage. The public class stays clean this way.

class FooPrivate {
public:
    // only public stuff in here;
    // and especially this:
    static FooPrivate *get(Foo *f) { return f->d; }
};

The test then includes the private header and calls FooPrivate::get(fooObj) to get the private class instance and then happily uses it.

半枫 2024-12-11 06:05:14

我不同意“私有成员是实现细节”的心态,在我看来,这大致可以翻译为“仅测试代码的一部分”。

我可以与“单位就是单位”的论点相关,但为什么不尝试用测试覆盖尽可能多的代码,即使是在单位内部?又名。 对您的单位进行彻底的直肠检查

考虑到这一点,我经常使用的一种在其他答案中未提及的方法是执行以下操作:

  1. 始终将要测试的成员声明为 protected 而不是 private 在你的代码中。
  2. 在测试代​​码中对您的类进行子类化,然后简单地创建您需要的选择器,或者直接将测试代码编写为该子类实现中的成员。

注意:您必须小心对待依赖于复杂实例化模式的类,以确保正确构造它们(阅读:从子类构造函数调用原始类的构造函数)。

I disagree with the "private members are implementation details" mentality, in my mind that roughly translates to "test only part of your code".

I can related to "units are units" argument, but why not try to cover as much of your code with tests as possible, even inside units? Aka. giving your units a thorough rectal examination.

And with this image in mind, one approach that I have been using frequently that is not mentioned in the other answers is to do the following:

  1. Always declare members you want to test as protected in stead of private in your code.
  2. Subclass your class in the testcode and simply make the selectors you need or simply write the test-code directly as members in that sub-class's implementation.

NOTE: You have to be careful with classes that rely on complex instantiation patterns to ensure that you construct them correctly (read: call the original class' constructor from the subclass ctor).

堇年纸鸢 2024-12-11 06:05:14

我找到了更方便的方法来做到这一点。首先,所有私有方法都应该是私有槽。
然后创建该类的一个实例:

Foo a;

然后我们可以使用 QMetaObject::invokeMethod 来调用该方法具有的任何槽(公共或私有)。因此,如果我们想调用方法 Test,我们可以这样做:

QMetaObject::invokeMethod(&a, "Test", Qt::DirectConnection);

另外,我们可以有返回值并发送参数...实际上,一切都在这里得到解答: http://doc.qt.nokia.com/stable/qmetaobject.html#invokeMethod

I have found more convenient way to do this. First, all private methods should be private slots.
Then you create an instance of the class:

Foo a;

Then we can use QMetaObject::invokeMethod to call any slot that method has (public or private). So if we want to call method Test, we can do it like this:

QMetaObject::invokeMethod(&a, "Test", Qt::DirectConnection);

Also, we can have return value and send arguments ... Actually, everything is answered here: http://doc.qt.nokia.com/stable/qmetaobject.html#invokeMethod

删除会话 2024-12-11 06:05:14

我曾经读过,单元测试应该测试类公共接口,而不是受保护/私有的东西。

你的班级在外面应该表现得端正。如果实施策略发生变化,您的单元测试类仍然相同。

I've once read that Unit Test should test the class public interface, and not the protected/private stuff.

Your class should just behave right from outside. If implementation strategy changes, your Unit Test class is still the same.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文