您有很多选择。正如您所说,其中一个选项是创建接口。假设您有类
class Engine:
{
public:
void start(){ };
};
class Car
{
public:
void start()
{
e_.start();
private:
Engine e;
};
介绍接口 - 你需要将Car更改为接受Engine
class Car
{
public:
Car(Engine* engine) :
e_(engine)
{}
void start()
{
e_->start();
private:
Engine *e_;
};
如果你只有一种类型的引擎,那么你的汽车对象将变得更难使用(谁创建引擎,谁拥有引擎)。汽车有很多部件 - 所以这个问题将会不断增加。
如果你想要不同的实现,还可以使用模板。这样就不需要接口了。
class Car<type EngineType = Engine>
{
public:
void start()
{
e_.start();
private:
EngineType e;
};
在你的模拟中,你可以使用专门的引擎创建汽车:
Car<MockEngine> testEngine
另一种不同的方法是向引擎添加方法以进行测试,类似于以下内容:
class Engine:
{
public:
void start();
bool hasStarted() const;
};
你可以在Car类中添加一个检查方法,或者从Car继承来测试。
class TestCar : public Car
{
public:
bool hasEngineStarted() { return e_.hasStarted(); }
};
这将需要将Car类中的Engine从private更改为protected。
根据实际情况,最佳解决方案会有所不同。此外,每个开发人员都有自己认为代码应该如何进行单元测试的方法。我的个人观点是要考虑客户/用户。假设您的客户(可能是团队中的其他开发人员)将创建汽车而不关心引擎。因此,我不希望暴露引擎的概念(一个库内部的类),只是为了进行单元测试。我选择不创建接口并将两个类一起测试(我提供的第三个选项)。
Car
,而Car
依赖于一个Engine
类。为了确保我进行的是单元测试而不是集成测试,我需要模拟Engine
类(并以某种方式让Car
使用我的模拟Engine
)。否则,我就在测试两个类并进行集成测试,而不是单元测试。为了轻松地模拟Engine
类,它似乎需要是一个接口。 - User