Qt 中是否可以对私有方法进行单元测试(访问)?
我正在为我的应用程序编写单元测试,现在我偶然发现了一个应该在其中测试私有方法的类。这可能是特定课程设计不当的结果,但我必须这样做。 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
正确的(读起来烦人的)答案是您不应该测试私有方法,这些是实现细节
;-)
。OTOH - 您是否考虑过有条件地声明它们受保护/私有,具体取决于您是否正在进行测试,然后进行扩展?我过去曾用它来摆脱类似的困境。
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.
解决方案 1,快速且简单:使测试类成为公共类的朋友。
这样您的 FooTest 类就可以访问公共类的所有成员。然而,这样,每次想要从不同的测试访问私有数据时,都需要修改原始类,并且会泄漏公共 API 中有关测试的信息,并且可能会出现类命名冲突(如果有/怎么办)另一个/ FooTest 类周围?),等等。
解决方案2,又名正确完成:不要将私有方法放在公共类中,而是使用公共方法创建私有类。
FooPrivate
在其自己的标头中声明,该标头可能不会安装,或者保留在 include-privates/ 子目录中,或者其他什么 - 即它不会妨碍正常使用。这样公共课就保持干净了。然后,测试包含私有标头并调用 FooPrivate::get(fooObj) 来获取私有类实例,然后愉快地使用它。
Solution 1, quick and easy: make the test class(es) a friend of the public one.
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.
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.The test then includes the private header and calls
FooPrivate::get(fooObj)
to get the private class instance and then happily uses it.我不同意“私有成员是实现细节”的心态,在我看来,这大致可以翻译为“仅测试代码的一部分”。
我可以与“单位就是单位”的论点相关,但为什么不尝试用测试覆盖尽可能多的代码,即使是在单位内部?又名。 对您的单位进行彻底的直肠检查。
考虑到这一点,我经常使用的一种在其他答案中未提及的方法是执行以下操作:
protected
而不是private
在你的代码中。注意:您必须小心对待依赖于复杂实例化模式的类,以确保正确构造它们(阅读:从子类构造函数调用原始类的构造函数)。
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:
protected
in stead ofprivate
in your code.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).
我找到了更方便的方法来做到这一点。首先,所有私有方法都应该是私有槽。
然后创建该类的一个实例:
然后我们可以使用 QMetaObject::invokeMethod 来调用该方法具有的任何槽(公共或私有)。因此,如果我们想调用方法 Test,我们可以这样做:
另外,我们可以有返回值并发送参数...实际上,一切都在这里得到解答: 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:
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:
Also, we can have return value and send arguments ... Actually, everything is answered here: http://doc.qt.nokia.com/stable/qmetaobject.html#invokeMethod
我曾经读过,单元测试应该测试类公共接口,而不是受保护/私有的东西。
你的班级在外面应该表现得端正。如果实施策略发生变化,您的单元测试类仍然相同。
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.