如果我有一个包含辅助(私有成员)类的类,就像这样
class Obj;
class Helper {
friend class Obj;
private:
int m_count;
Helper(){ m_count = 0;}; // Note this is a private constructor
void incrementCount(){
++m_count;
};
};
class Obj {
Helper *m_pHelper;
// note that this is a private getter
int getHelperCount() { return m_pHelper->m_count; };
// the public API starts here
public:
Obj() { m_pHelper = new Helper(); };
void incrementCount(){ m_pHelper->incrementCount(); };
};
那么我怎么可能TDD这样的系统呢?
auto obj = new Obj();
obj->incrementCount();
// what to assert???
这是我的问题,以下只是一些背景知识。
如果课外没有人感兴趣,那么你的测试也不应该感兴趣。 - Arne Mertz
如果没有人对课外的价值感兴趣,你为什么 - utnapistim
即使外面没有人需要该值,我仍然可能想知道如果它设置正确,因为它被使用该值的类的其他自包含内部方法使用。也许值是控制器用它来更新模型的速度。或者它可能是视图将用它在屏幕上绘制内容的位置。事实上,Obj的所有其他组件都能够访问该变量。这可能是一个糟糕的设计问题,在这种情况下,我想知道我可以有更好的替代方案。该设计列于本文底部的背景部分。
定义私人公众 - Marson Mao
喜欢这种巧妙滥用关键词哈哈。但可能还不是最佳解决方案。
您需要在班级标题中“公开”友谊关系。因此,你必须承认存在一个用来测试你的类。 如果你使用pImpl惯用法,你可以使pImpl本身的成员全部公开,pImpl本身是私有的,并让你的单元测试访问pImpl - CashCow
这是否意味着我应该在我原来的课堂上为考试做好准备?或者为它添加额外的“测试”方法? 我刚刚开始使用TDD。使用测试类依赖项来侵入原始类是否常见(或更好)?我不认为我有适当的知识来判断。对此有何建议?
杂项:AFAIK TDD不只是编写测试,而是开发过程。我已经读过,我应该只对公共接口编写测试。但问题是,与所讨论的情况一样,大多数代码都包含在私人类中。我如何使用TDD创建这些代码?
仅供参考,如果您想知道我为什么要上私人课程: 我正在开发一个来自cocos2dx的游戏。游戏引擎采用节点树结构进行更新,渲染等,每个游戏对象都将继承引擎中提供的Node类。现在我想在游戏对象上实现MVC模式。因此,对于每个对象,我基本上创建了一个Object类,其中包含3个辅助类,这些类对应于名为ObjectModel,ObjectView,ObjectController的每个MVC组件。从理论上讲,没有人应该直接访问MVC类,只能通过Object类以某种方式访问它,所以我将其中的3个私有化。将MVC组件明确地作为类的原因是因为视图和控制器以不同的速率更新(更具体地,控制器执行依赖于帧的更新,而视图基于模型数据执行简单的插值)。 Model类是纯粹出于宗教原因而创建的。
提前致谢。
答案 0 :(得分:4)
如何测试私人班级的朋友功能?
你不可以!
类(或模块或库或其他)出于某种原因公开公共接口。你有公共接口(适合客户端使用,因此它具有不变量,前置条件,后置条件,副作用,无论什么 - 可以并且应该测试)和实现细节,使您可以更轻松地实现公共接口。
拥有私有实现的关键是,您可以随意更改它,而不会影响其他代码(不会影响测试)。更改私有实现后,所有测试都应该通过,客户端(和测试)代码应该(按设计)完全不关心您更改了私有实现。
那么我怎么可能TDD这样的系统呢?
仅限TDD您的公共界面。测试实现细节意味着您最终编码到实现,而不是接口。
关于你的评论:
问题是我甚至没有在公共界面中使用getter。那么我的测试如何检查该值是0还是1?并且有意将getter私有化,因为没有人应该对类外的价值感兴趣
如果没有人对课外的价值感兴趣,你为什么要这样做(也就是为什么要测试它呢?)
答案 1 :(得分:1)
我在编写单元测试时也遇到过这样的问题。
经过一番搜索,我认为最有效的方法是在Test.cpp
中添加:
#define private public
注意:在您想要的包含文件之前添加此文件,例如您的Obj.h
。
我认为这种方法看起来很疯狂但实际上是合理的,因为#define
只会影响您的测试文件,因此使用Obj.h
的所有其他人都完全没问题。
一些参考:
答案 2 :(得分:1)
正如@Marson Mao所说,我投票给#define私人公众。
如果你想更多地控制私人或公开的内容,可以在yourtests.cpp中执行此操作
#define private public
#include "IWantAccessViolationForThis.h"
#undef private
#include "NormalFile.h"
通过这种方式,您可以获得更多控制权并尝试在尽可能少的地方执行此操作。
这种方法的另一个不错的特性是它是非侵入性的,这意味着您不需要使用#ifdef来混淆真实的实现和头文件以进行测试而不是测试模式。
答案 3 :(得分:1)
#define私有公共技巧可能会产生副作用,因为某些编译器会修改函数符号(Visual c ++编译器在其名称中包含访问说明符)
您还可以使用using语句更改可见性:
struct ObjTest : public Obj
{
using Obj::incrementCount;
}
但就像其他人说的那样,如果可能的话,尽量不要测试私人内容。
答案 4 :(得分:0)
您的朋友可以完全访问该朋友的课程。这可能有很多原因,其中一个可能是 单元测试 目的,即您希望能够编写可以调用私有成员的单元测试该类的内部变量显示了您希望它们显示的内容,但您不希望它成为公共API的一部分。
您需要在班级标题中“公开”友谊关系。因此,你必须承认存在一个用来测试你的类。不用担心,你在现实世界中发展,并对课程进行测试。
为了编写单元测试,您需要实现该类以提供调用所有相关私有函数或获取私有成员的受保护成员函数(可能是静态函数),然后编写派生自您的类。请注意,那些不会直接访问,因为友谊不会被继承,因此静态受保护的成员。
如果你使用pImpl惯用法,你可以使pImpl本身的成员全部公开,pImpl本身是私有的,并让你的单元测试访问pImpl(通过与上面相同的模型)。这现在更简单,因为您只需要为“测试人员”创建一个方法。
关于类的数据成员,近年来我已经知道将所有这些都放入一个结构中,即将它们全部公开,然后让类具有该结构的私有实例。它可以更容易处理这类事情,也可以更容易地序列化/工厂到类,在那里他们可以创建全部公开的结构,然后从中构建你的类。