14

目前我的项目由各种具体的类组成。现在,当我开始进行单元测试时,看起来我应该为每个类创建一个接口(实际上使我的项目中的类数量增加了一倍)?我碰巧使用 Google Mock 作为模拟框架。请参阅有关接口的 Google Mock CookBook。虽然之前我可能只有类CarEngine,但现在我将拥有抽象类(也称为 C++ 接口)CarEngine然后是实现类CarImplementationEngineImpl或其他。这将允许我消除CarEngine.

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

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

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

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

4

3 回答 3

6

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

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

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

private:
    Engine e;
};

要引入接口 - 您必须更改 Car 以获取 Engine

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

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

private:
    Engine *e_;
};

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

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

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

private:
    EngineType e;
};

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

Car<MockEngine> testEngine;

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

class Engine:
{
public:
    void start();
    bool hasStarted() const;
};

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

class TestCar : public Car
{
public:
    bool hasEngineStarted() { return e_.hasStarted(); }
};

这将需要在 Car 类中将 Engine 从私有更改为受保护。

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

于 2011-07-27T12:15:33.193 回答
1

关于实现可见性有两类测试:黑盒测试和白盒测试

  • 黑盒测试侧重于通过其接口测试实现,并验证对其规范的调整。

  • 白盒测试测试有关通常不应该从外部访问的实现的详细细节。这种测试将验证实现组件是否按预期工作。因此,他们的结果对试图找出损坏或需要维护的开发人员最感兴趣

根据他们的定义,模拟适合模块化架构,但并不意味着项目中的所有类都需要完全模块化。当一组班级彼此了解时,画一条线是完全可以的。它们作为一个组可以从某些外观接口类的角度呈现给其他模块。但是,您仍然希望在此模块中拥有白盒测试驱动程序,并了解实现细节。因此,这种测试不适合模拟

从中可以轻松得出结论,您不需要为所有内容都提供模拟或接口。只需采用实现外观接口的高级设计组件并为它们创建模拟。它将为您提供模拟测试带来回报的最佳位置,恕我直言

话虽如此,请尝试根据您的需要使用该工具,而不是让该工具强迫您进行您认为从长远来看不会有益的更改

于 2011-07-12T20:09:19.463 回答
0

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

我会检查您要测试的内容,并专注于您认为最容易出错的领域。这可以帮助您决定是否需要接口。

于 2011-07-08T01:56:50.043 回答