我如何模拟标记为最终的课程?

问题描述 投票:0回答:0

我需要向类 (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;
    };
};

我找到了三种方法来解决这个问题。也许还有另一个更好的解决方案(我希望如此:))

  1. 第一个是模板化 SensorCLient,因此,在测试期间模拟 VelocitySensor 应该很容易。
#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>;
};

对我来说,它看起来相当不错。但也许还有另一种不需要使用模板的解决方案。

  1. 第二个是使用适配器模式。
#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 的问题移到了一个新类中。我想处理代码覆盖率......所以这不是我的解决方案。

  1. 粉刺

我想我可以使用 Pimpl idom 在 cpp 文件中隐藏实现细节(包括指向 VelocityObject 的指针),因此,我应该能够模拟实现(现在我不需要模拟 VelocitySensor) .但在那种情况下,单元测试不会涵盖实现。 :( 我发现了一些关于使用工厂来解决这个问题的东西,但我不确定在我的情况下如何使用它,

编辑 2-05-2023 关于代理和我的问题,谢谢@Pepijn Kramer,我想我明白了。我有两个选择:模板或代理。

为了防止VelocitySensor和SensorClient强耦合,我需要定义一个代理类。代理与 VelocitySensor 强耦合,但使用此代理的 SensorClient 仅与代理实现的接口强耦合。要向 SensorClient 添加单元测试,我需要模拟所有依赖项,这假定 SensorClient 应该与其依赖项松散耦合。通过proxy,就不是这样了,所以我们不能为proxy写单元测试,但是我们可以给它加上集成测试。 现在,我可以向 VelocitySensor 的 SensorClient 和模拟代理添加测试 :) .

我假设如果我想实现100%的代码覆盖率,我需要给所有东西(包括代理、适配器等)添加UT。 据我了解,有时这是不可能的。

c++ testing design-patterns dependency-injection software-design
© www.soinside.com 2019 - 2024. All rights reserved.