c++中的TDD.如何测试private类的好友函数

TDD in C++. How to test friend functions of private class?

本文关键字:private 函数 好友 测试 TDD 中的 何测试 c++      更新时间:2023-10-16

如果我有一个类里面有一个助手(私有成员)类,像这样

    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的所有其他组件都可以访问这个变量。这可能是一个糟糕的设计问题,在这种情况下,我想知道我可以有什么更好的替代方案。该设计在本文底部的背景部分列出。

喜欢这个巧妙的滥用关键词哈哈。但它可能还不是最好的解决方案。

你需要"曝光"你们班头的友谊关系。因此,您必须承认存在一个用于测试您的类。如果您使用pImpl习惯用法,您可以使pImpl本身的成员都是公共的,pImpl本身是私有的,并允许您的单元测试访问pImpl - CashCow

这是否意味着我应该将测试添加到我原来的班级中?或者添加额外的"测试";方法?我最近才开始使用TDD。使用测试类依赖来入侵原始类是常见的(或者更好)吗?我不认为我有足够的知识来判断。对此有什么建议吗?

杂项:据我所知,TDD不仅仅是编写测试,而是一个开发过程。我读到过应该只编写公共接口的测试。但问题是,就像问题中的情况一样,大多数代码等都包含在私有类中。我如何使用TDD来创建这些代码?

的背景

供参考,如果你想知道为什么我做一个私人类:我正在开发一款来自cocos2dx的游戏。游戏引擎采用节点树结构进行更新、渲染等,每个游戏对象都将继承引擎中提供的Node类。现在我想在一个游戏对象上实现MVC模式。所以对于每个对象,我基本上创建了一个object类和3个辅助类对应于每个MVC组件ObjectModel ObjectView ObjectController。理论上,没有人应该直接访问MVC类,只能通过Object类以某种方式访问,所以我使它们中的3个私有。将MVC组件显式地制作为类的原因是因为视图和控制器以不同的速率更新(更具体地说,控制器执行依赖于帧的更新,而视图根据模型数据进行简单的插值)。Model类的创建纯粹是出于宗教原因,哈哈。

提前感谢。

如何测试private类的友元函数?

你不应该!

类(或模块、库或其他)公开公共接口是有原因的。你有了公共接口(它是为客户端使用而设计的,所以它有不变量、前提条件、后置条件、副作用,无论什么——这些都可以而且应该被测试)和实现细节,这使你可以更容易地实现公共接口。

私有实现的意义在于,你可以随心所欲地改变它,而不影响其他代码(甚至不影响测试)。在您更改私有实现之后,所有测试都应该通过,并且客户端(和测试)代码应该(根据设计)完全不关心您更改了私有实现。

那么我该如何TDD这样一个系统呢?

仅TDD您的公共接口。测试实现细节意味着你最终要为实现编码,而不是为接口编码。

关于你的评论:

问题是我甚至在公共接口中都没有getter。那么我的测试如何检查值是0还是1呢?getter被故意设置为私有的因为没有人会对

类之外的值感兴趣

如果没有人对类之外的值感兴趣,为什么你要测试它呢?

#define private public技巧可能会对某些编译器混淆函数符号的方式产生副作用(Visual c++编译器在其名称中包含访问说明符mangling)

你也可以用using语句改变可见性:

struct ObjTest : public Obj
{
   using Obj::incrementCount;
}

但是就像其他人说的,如果可能的话,尽量不要测试私人的东西。

我在编写单元测试时也遇到过这样的问题。

经过一番搜索,我决定最有效的方法是将此添加到您的Test.cpp:

#define private public

注意:在你想要的包含文件之前添加这个,比如你的Obj.h

我认为这个方法看起来很疯狂,但它实际上是合理的,因为这个#define只影响你的测试文件,所以所有其他人使用你的Obj.h是完全好的。

参考:

如果你想控制什么是私有的或公共的,你可以在你的测试。cpp

#define private public
#include "IWantAccessViolationForThis.h"
#undef private
#include "NormalFile.h"

这样你可以有更多的控制,并尝试在尽可能少的地方做这个技巧。

这种方法的另一个优点是它是非侵入性的,这意味着您不需要在实际实现和头文件中使用#ifdefs来测试和不测试模式。

好友对其所属的类具有完全访问权限。这可能有很多原因,其中一个很可能是为了单元测试目的,也就是说,你希望能够编写一个单元测试,可以调用类的私有成员,并检查内部变量是否显示你希望它们显示的内容,但你不希望它成为公共API的一部分。

你需要在类的头文件中"公开"友谊关系。因此,您必须承认存在一个用于测试您的类。不用担心,你是在现实世界中开发的,类是经过测试的。

为了编写单元测试,您将需要实现该类来提供受保护的成员函数(可能是静态的),这些成员函数调用所有相关的私有函数或获取私有成员,然后您编写派生自您的类。请注意,这些成员不能直接访问,因为友谊是不可继承的,因此是静态受保护成员。

如果您使用pImpl习语,您可以使pImpl本身的所有成员都是公共的,pImpl本身是私有的,并允许您的单元测试访问pImpl(通过与上面相同的模型)。这就简单多了,因为你只需要为你的"测试器"创建一个方法。

关于类的数据成员,近年来我已经知道将所有这些数据成员放入一个结构体中,即使它们都是公共的,然后为类提供该结构体的私有实例。它可以更容易地处理这类事情,也序列化/工厂到你的类,在那里他们可以创建结构,这是所有的公共,然后从它构造你的类。

相关文章: