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