我需要向类 (SensorClient) 添加单元测试,该类包含指向标记为最终类 (VelocitySensor) 的对象的指针。重要的是我不能修改 VelocitySensor 类。因此,我无法将 VelocitySensor 方法更改为虚拟...另外,我想避免使用#define 的任何“朋友”类或技巧。
速度传感器类:
//sensor_service.hpp
#pragma once
#include <string>
namespace sensor
{
class VelocitySensor final
{
public:
VelocitySensor() : velocity(20), sensorName("VelocitySensor") {}
double getVelocity() const
{
return velocity;
}
std::string getSensorName() const
{
return sensorName;
}
void calculateSomething()
{
const double time = 10;
auto vel = getVelocity();
auto distance = vel * time;
//...
}
private:
std::string sensorName;
double velocity;
};
}
传感器客户端类:
//sensor_client.hpp
#pragma once
#include "sensor_service.hpp"
#include <memory>
#include <iostream>
namespace sensor
{
class SensorClient
{
public:
SensorClient() : sensor(std::make_unique<VelocitySensor>()) {}
double getVelocity() const
{
return sensor->getVelocity();
}
void calculateNumOfTyres()
{
sensor->calculateSomething();
}
std::string getVehicleName() const
{
return sensor->getSensorName();
}
private:
std::unique_ptr<VelocitySensor> sensor;
};
};
我找到了三种方法来解决这个问题。也许还有另一个更好的解决方案(我希望如此:))
#pragma once
#include "sensor_service.hpp"
#include <memory>
#include <iostream>
namespace sensor
{
template <typename T>
class SensorClientTemplate
{
public:
SensorClientTemplate(std::unique_ptr<T> _sensor = std::make_unique<VelocitySensor>())
: sensor(std::move(_sensor)) {}
virtual ~SensorClientTemplate() = default;
double getVelocity() const
{
return sensor->getVelocity();
}
void calculateSomething()
{
sensor->calculateSomething();
}
std::string getSensorName() const
{
return sensor->getSensorName();
}
private:
std::unique_ptr<T> sensor;
};
using SensorClient = SensorClientTemplate<SensorService>;
};
对我来说,它看起来相当不错。但也许还有另一种不需要使用模板的解决方案。
#pragma once
#include "sensor_service.hpp"
#include <memory>
#include <iostream>
namespace sensor
{
class ISensor
{
public:
virtual ~ISensor() = default;
virtual double getVelocity() const = 0;
virtual std::string getSensorName() const = 0;
virtual void calculateSomething() = 0;
};
class SensorAdapter : public ISensor
{
public:
void calculateSomething() override
{
sensor.calculateSomething();
}
double getVelocity() const override
{
return sensor.getVelocity();
}
std::string getSensorName() const override
{
return sensor.getSensorName();
}
private:
VelocitySensor sensor;
};
class SensorClient
{
public:
SensorClient(std::unique_ptr<ISensor> _sensor = std::make_unique<SensorAdapter>())
: sensor(std::move(_sensor)) {}
virtual ~SensorClient() = default;
double getVelocity() const
{
return sensor->getVelocity();
}
void calculateSomething()
{
sensor->calculateSomething();
}
std::string getSensorName() const
{
return sensor->getSensorName();
}
private:
std::unique_ptr<ISensor> sensor;
};
};
现在我在向适配器类添加测试时遇到问题......我将模拟 VelocitySensor 的问题移到了一个新类中。我想处理代码覆盖率......所以这不是我的解决方案。
我想我可以使用 Pimpl idom 在 cpp 文件中隐藏实现细节(包括指向 VelocityObject 的指针),因此,我应该能够模拟实现(现在我不需要模拟 VelocitySensor) .但在那种情况下,单元测试不会涵盖实现。 :( 我发现了一些关于使用工厂来解决这个问题的东西,但我不确定在我的情况下如何使用它,
编辑 2-05-2023 关于代理和我的问题,谢谢@Pepijn Kramer,我想我明白了。我有两个选择:模板或代理。
为了防止VelocitySensor和SensorClient强耦合,我需要定义一个代理类。代理与 VelocitySensor 强耦合,但使用此代理的 SensorClient 仅与代理实现的接口强耦合。要向 SensorClient 添加单元测试,我需要模拟所有依赖项,这假定 SensorClient 应该与其依赖项松散耦合。通过proxy,就不是这样了,所以我们不能为proxy写单元测试,但是我们可以给它加上集成测试。 现在,我可以向 VelocitySensor 的 SensorClient 和模拟代理添加测试 :) .
我假设如果我想实现100%的代码覆盖率,我需要给所有东西(包括代理、适配器等)添加UT。 据我了解,有时这是不可能的。