单元测试:接口编码?

Use*_*ser 14 c++ unit-testing interface concrete googlemock

目前我的项目由各种具体课程组成.现在,当我进入单元测试时,看起来我应该为每个类创建一个接口(有效地将项目中的类数量加倍)?我碰巧使用Google Mock作为模拟框架.请参阅接口上的Google Mock CookBook.虽然之前我可能刚刚类CarEngine,现在我将有抽象类(又称C++接口)CarEngine然后实现类CarImplementationEngineImpl或什么的.这将使我能够Car依赖它Engine.

我在研究这个问题时遇到了两条思路:

  1. 仅当您可能需要对给定抽象的多个实现和/或在公共API中使用时才使用接口,否则不要不必要地创建接口.

  2. 单元测试存根/模拟通常 "其他实现",因此,是的,您应该创建接口.

在单元测试时,我应该为项目中的每个类创建一个接口吗?(我倾向于创建易于测试的界面)

Wil*_*ill 5

认为你有很多选择.如你所说,一种选择是创建接口.说你有课

class Engine:
{
public:
    void start(){ };
};

class Car
{
public: 
    void start()
    {
        // do car specific stuff
        e_.start();

private:
    Engine e;
};
Run Code Online (Sandbox Code Playgroud)

要引入接口 - 您必须将Car更改为引擎

class Car
{
public: 
    Car(Engine* engine) :
    e_(engine)
    {}

    void start()
    {
        // do car specific stuff
        e_->start();

private:
    Engine *e_;
};
Run Code Online (Sandbox Code Playgroud)

如果您只有一种类型的引擎 - 您突然使您的Car对象更难使用(谁创建引擎,谁拥有引擎).汽车有很多部件 - 所以这个问题会继续增加.

如果您想要单独实现,另一种方法是使用模板.这消除了对接口的需求.

class Car<type EngineType = Engine>
{
public: 
    void start()
    {
        // do car specific stuff
        e_.start();

private:
    EngineType e;
};
Run Code Online (Sandbox Code Playgroud)

在您的模拟中,您可以创建具有专用引擎的汽车:

Car<MockEngine> testEngine;
Run Code Online (Sandbox Code Playgroud)

另一种不同的方法是向Engine添加方法以允许对其进行测试,例如:

class Engine:
{
public:
    void start();
    bool hasStarted() const;
};
Run Code Online (Sandbox Code Playgroud)

然后,您可以向Car添加检查方法,或者从Car继承进行测试.

class TestCar : public Car
{
public:
    bool hasEngineStarted() { return e_.hasStarted(); }
};
Run Code Online (Sandbox Code Playgroud)

这将要求Engine在Car类中从private更改为protected.

根据现实情况,将取决于哪种解决方案最好.此外,每个开发人员都有自己的圣杯,他们如何相信代码应该进行单元测试.我个人的观点是牢记客户/客户.让我们假设您的客户(可能是您团队中的其他开发人员)将创建汽车并且不关心引擎.因此,我不想公开Engines(我的库内部的类)的概念,因此我可以对事物进行单元测试.我会选择不创建接口并一起测试这两个类(我给出的第三个选项).


Ada*_*oll 0

为项目中的每个类创建接口可能有必要,也可能没有必要。这完全是一个设计决定。我发现大部分情况并非如此。通常,在n 层设计中,您希望抽象数据访问和逻辑之间的层。我认为您应该朝这个方向努力,因为它有助于测试逻辑,而无需太多测试所需的基础设施。诸如依赖注入和 IoC 之类的抽象方法将要求您执行类似的操作,并且可以更轻松地测试所述逻辑。

我会检查您正在尝试测试的内容,并重点关注您认为最容易出错的领域。这可以帮助您决定接口是否必要。