You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Google Test框架测试类Getter时,如何避免频繁修改构造函数参数?

解决Google Test中构造函数扩展导致旧测试失效的问题

这确实是个常见的测试痛点——每次扩展weatherdayRecord的构造函数都要回头修改一堆旧测试,太折腾了。给你几个实用的方案来避免这种情况:

方案1:给构造函数添加默认参数

最简单的办法是修改weatherdayRecord的构造函数,给新增的参数设置合理的默认值。这样旧测试里只传部分参数的代码依然能正常编译,不用修改。

比如把构造函数改成这样:

class weatherdayRecord {
public:
    // 给date参数加默认值,旧代码只传city也能正常工作
    weatherdayRecord(std::string city, std::string date = "") {
        // 原有的验证逻辑
        if (!isValidCity(city)) throw std::invalid_argument("Invalid city");
        if (!date.empty() && !isValidDate(date)) throw std::invalid_argument("Invalid date");
        // ... 初始化成员变量
    }

    // ... Getter方法
};

这样你的旧测试代码完全不用改,新测试需要测试日期时再传第二个参数:

TEST_F(wsRecordTest,DoesItThrowExceptionWhenWrongCitynameIsProvided) {
    // 旧代码保持不变,依然有效
    weatherdayRecord wsRecord{"!#Delft$*"};
    ASSERT_THROW(wsRecord.getCity(),std::invalid_argument);
}

TEST_F(wsRecordTest,DoIGetTheRightDateFromTheConstructor) {
    // 新测试传完整参数
    weatherdayRecord wsRecord{"Delft","2020-10-03"};
    ASSERT_EQ(wsRecord.getDate(),"2020-10-03");
}

方案2:使用构建器模式(Builder Pattern)

如果未来还要添加更多字段,默认参数可能会变得杂乱,这时候构建器模式更适合。创建一个weatherdayRecordBuilder类,允许你逐步设置需要的字段,最后生成对象。

示例代码:

class weatherdayRecord {
private:
    // 把构造函数设为私有,强制通过Builder创建
    weatherdayRecord(std::string city, std::string date) {
        // 验证逻辑
        if (!isValidCity(city)) throw std::invalid_argument("Invalid city");
        if (!isValidDate(date)) throw std::invalid_argument("Invalid date");
        // ... 初始化成员
    }

    // Getter方法...

public:
    class Builder {
    private:
        std::string city_;
        std::string date_ = "2020-01-01"; // 默认日期

    public:
        Builder& setCity(std::string city) {
            city_ = std::move(city);
            return *this;
        }

        Builder& setDate(std::string date) {
            date_ = std::move(date);
            return *this;
        }

        weatherdayRecord build() {
            return weatherdayRecord(city_, date_);
        }
    };
};

测试时只需要设置当前关心的字段:

TEST_F(wsRecordTest,DoesItThrowExceptionWhenWrongCitynameIsProvided) {
    // 只设置城市名,日期用默认值
    ASSERT_THROW(weatherdayRecord::Builder().setCity("!#Delft$*").build(), std::invalid_argument);
}

TEST_F(wsRecordTest,DoIGetTheRightDateFromTheConstructor) {
    auto wsRecord = weatherdayRecord::Builder()
                        .setCity("Delft")
                        .setDate("2020-10-03")
                        .build();
    ASSERT_EQ(wsRecord.getDate(),"2020-10-03");
}

这样就算以后添加更多字段(比如温度、湿度),只需要在Builder里加对应的setXXX方法,旧测试完全不用修改。

方案3:在测试夹具中封装实例创建逻辑

利用Google Test的测试夹具(Test Fixture),在wsRecordTest类里封装创建不同实例的方法,避免测试代码直接写构造函数。

示例:

class wsRecordTest : public ::testing::Test {
protected:
    // 创建只设置城市名的实例(日期用默认值)
    weatherdayRecord createRecordWithCity(const std::string& city) {
        return weatherdayRecord{city, "2020-01-01"}; // 假设构造函数现在需要两个参数
    }

    // 创建完整参数的实例
    weatherdayRecord createFullRecord(const std::string& city, const std::string& date) {
        return weatherdayRecord{city, date};
    }
};

测试时调用这些方法:

TEST_F(wsRecordTest,DoesItThrowExceptionWhenWrongCitynameIsProvided) {
    ASSERT_THROW(createRecordWithCity("!#Delft$*"), std::invalid_argument);
}

TEST_F(wsRecordTest,DoIGetTheRightDateFromTheConstructor) {
    auto wsRecord = createFullRecord("Delft","2020-10-03");
    ASSERT_EQ(wsRecord.getDate(),"2020-10-03");
}

如果以后构造函数参数变了,只需要修改夹具里的createRecordWithCity和createFullRecord方法,所有测试代码都不用改,维护成本低很多。

内容的提问来源于stack exchange,提问作者Bluewave1976

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 17:27:32