除了模拟测试之外,还无需额外使用接口

Coding to an interface without an additional use of the interface aside from mocking for tests?

本文关键字:接口 模拟 测试      更新时间:2023-10-16

我最近一直在尝试在工作中应用TDD,并且当我需要思考最佳模拟方法时偶尔会挂断。我正在处理的工作涉及大量的网络请求和文件系统访问,因此无论如何都没有嘲笑。从Gmock文档中,我的理解是,模拟类的最佳选择是通过"编码到接口",或者通过模板。

这是我关于"编码到接口"的两个主要问题,此后我将举例说明我要问的内容:

  1. 当我目前没有其他界面的其他用途时,使用此方法仍然有意义吗?
  2. 现在,如果我继续"编码到接口",我只为嘲笑/测试而做。如果我只是传递要模拟的内容(谁从该界面继承)而不是传递该界面,我是否仍在"编码到接口"?我提出这个,因为有时感觉更可读。

#1 ...

的示例代码
class Thing {
  bool IsInstalled(); // multiple filesystem calls, I want to mock this method
};
bool Install(vector<Thing>& thingsToInstall) // before "coding to an interface"
bool Install(vector<unique_ptr<IInstallable>>& thingsToInstall) // after "coding to an interface"
class Thing : public IInstallable {
  bool IsInstalled() override;
};
class IInstallable {
  virtual bool IsInstalled() = 0;
};

我感兴趣的嘲笑行为是这些"事物"是否已安装。基于此,我可能会或可能不会执行网络请求(我已经嘲笑了)。因此,我不必绕过"事物"对象的向量,而必须将唯一_ptr的向量传递给iinstallable(我想模拟的行为/界面)。似乎很多,所以我只能对其进行测试,甚至无法重复使用界面。我想我想知道我确实在这里"编码到接口",这就是它的样子?您还可以详细说明它的何时且没有意义的"代码到接口"?

#2 ...

的示例代码
  bool Install(vector<unique_ptr<IInstallable>>& thingsToInstall) // original "coding to an interface" method from above

现在,我正在编码一个接口,因为我将围绕unique_ptrs传递到接口的唯一原因是我可以对其进行测试。有什么理由为什么我不应该将唯一的_ptr传递到实现Iinstallable接口的"事物"中?然后,我仍然可以直接从模拟课程中继承"事物"。我的代码也感觉更加可读性,因为我传递了一种与周围代码(事物)更相关的类型,而不是更通用的界面。但是,我什至不再"编码到接口"了吗?还是我只是完全破坏了"编码到接口"的目的(测试)?

这是最终方法的样子...

  bool Install(vector<unique_ptr<Thing>>& thingsToInstall) // Thing still implements IInstallable, so I can mock Thing directly

谢谢任何需要时间阅读并做出回应的人!非常感谢您的帮助。

我认为您的主要问题是关于这个参数的:

似乎很多,所以我只能测试它,甚至不重复使用界面。

但是您的coding to interface示例似乎不练习。定义接口确实需要仔细的设计,而不是"我想模拟它,以便它应该是接口"。

所以回到您的示例,您真正应该考虑的是,class Thing common接口是什么,是的,它应该具有bool IsInstalled();,但是还有什么?

假设您的真正class Thing在实践中具有两个功能,然后您将像这样定义界面:

class IThing {
  virtual bool IsInstalled() = 0;
  virtual void DoSomething() = 0;
};

然后您可以实现它:

class Thing : public IThing{
  bool IsInstalled() override;
  void DoSomething() override;
};

并这样使用:

bool Install(vector<unique_ptr<IThing>>& thingsToInstall);

现在您有机会:

  1. 在您的功能中使用IThing;
  2. 创建Thing并将IThing传递到生产代码中的功能;
  3. 创建MockIThing并将IThing传递到测试代码中的功能。