Spring配置类与外部属性单元测试实践指南

Spring配置类与外部属性单元测试实践指南

本文深入探讨了在Spring框架中,如何为依赖外部配置属性的@Configuration类编写有效的单元测试。针对属性无法正确注入导致测试失败的常见问题,教程提供了多种解决方案,包括使用@PropertySource、理解@DependsOn的适用性,以及Spring Boot中@ConfigurationPropertiesScan的现代实践,旨在帮助开发者构建健壮的配置测试。

引言:配置类单元测试的挑战

在spring应用中,@configuration类是定义和配置bean的核心。当这些配置bean依赖于通过@configurationproperties注解绑定的外部属性时,编写单元测试可能会遇到挑战。一个常见的场景是,尽管在测试环境中指定了属性文件,但@configurationproperties对象中的属性值仍然为空,导致bean创建失败。本文将基于一个具体的jms连接配置示例,深入探讨这一问题的原因及多种解决方案。

示例配置类概览

假设我们有一个用于JMS消息网关连接的配置类JmsMessageGatewayConnectionConfig,它依赖于JmsMessageGatewayProperties来获取连接参数:

@Configurationpublic class JmsMessageGatewayConnectionConfig {    @Bean    public JmsMessageGatewayConnection jmsMessageGatewayConnection (final JmsMessageGatewayProperties jmsConfig) throws JMSException {        // 使用jmsConfig和cachingConnectionFactory创建JmsMessageGatewayConnection        return new JmsMessageGatewayConnection(jmsConfig, cachingConnectionFactory(jmsConfig));    }    private CachingConnectionFactory cachingConnectionFactory(final JmsMessageGatewayProperties jmsConfig) {        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();        cachingConnectionFactory.setTargetConnectionFactory(jmsConnectionFactory(jmsConfig));        cachingConnectionFactory.resetConnection();        return cachingConnectionFactory;    }    private JmsConnectionFactory jmsConnectionFactory(final JmsMessageGatewayProperties jmsConfig) {        JmsConnectionFactory jmsConnectionFactory =                new JmsConnectionFactory(jmsConfig.getUsername(), jmsConfig.getPassword(), jmsConfig.getRemoteUri());        jmsConnectionFactory.setReceiveLocalOnly(true);        return jmsConnectionFactory;    }    @Bean    @ConfigurationProperties(prefix = "jms")    public JmsMessageGatewayProperties messageGatewayProperties() {        return new JmsMessageGatewayProperties();    }}

以及对应的属性类:

public class JmsMessageGatewayProperties {    private String remoteUri;    private String username;    private String password;    private boolean messagePersistent;    private Integer forceDetachedRetryLimit = 1;    // Getter和Setter方法省略    public String getRemoteUri() { return remoteUri; }    public void setRemoteUri(final String remoteUri) { this.remoteUri = remoteUri; }    // ... 其他属性的Getter/Setter}

我们的目标是测试JmsMessageGatewayConnection这个Bean是否能被Spring上下文正确地创建和注入。

初始测试尝试与问题分析

为了测试上述配置,我们通常会使用Spring的测试支持:

@RunWith(SpringRunner.class)@ContextConfiguration(classes = { JmsMessageGatewayConnectionConfig.class})@TestPropertySource(locations = "classpath:camel.properties")public class JmsMessageGatewayConnectionConfigTest {    @Autowired    private JmsMessageGatewayConnection jmsMessageGatewayConnection;    @Test    public void jmsMessageGatewayConnectionConfigTest() {        Assert.assertNotNull(jmsMessageGatewayConnection);    }}

并且在camel.properties文件中定义了jms前缀的属性:

jms.remoteUri=vm://localhost:61616jms.username=usernamejms.password=password

然而,上述测试会失败,并抛出Invalid URI: cannot be null or empty的错误。通过调试发现,JmsMessageGatewayProperties对象虽然被创建了,但其内部的remoteUri、username、password等属性值却为null。

问题根源在于,尽管@TestPropertySource加载了属性文件,但Spring容器在处理@ConfigurationProperties时,并没有自动将这些属性绑定到JmsMessageGatewayProperties实例上。@TestPropertySource主要负责将属性加载到Spring的Environment中,但@ConfigurationProperties的绑定机制还需要额外的配置来“激活”它。

解决方案

为了确保@ConfigurationProperties能够正确地从测试属性源中加载值,我们有以下几种主要策略:

方案一:在@ConfigurationProperties类或其配置上使用@PropertySource

最直接的解决方案是在JmsMessageGatewayProperties类上添加@PropertySource注解,或者在定义@ConfigurationProperties Bean的方法上添加。这明确告诉Spring从哪个文件加载这些属性。

推荐做法:在JmsMessageGatewayProperties类上添加@PropertySource

// JmsMessageGatewayProperties.java@PropertySource("classpath:camel.properties") // 添加此行public class JmsMessageGatewayProperties {    private String remoteUri;    private String username;    private String password;    // ... 其他属性及Getter/Setter}

通过这种方式,JmsMessageGatewayProperties类自身就携带着加载其属性的指令。当Spring容器扫描到这个类并尝试绑定jms前缀的属性时,它会知道去camel.properties中查找。

或者:在@Configuration类中通过@PropertySource加载

青柚面试 青柚面试

简单好用的日语面试辅助工具

青柚面试 57 查看详情 青柚面试

如果不想修改JmsMessageGatewayProperties类本身,也可以在JmsMessageGatewayConnectionConfig中加载属性:

@Configuration@PropertySource("classpath:camel.properties") // 添加此行,确保属性被加载到Environment中public class JmsMessageGatewayConnectionConfig {    // ... 保持原有代码不变    @Bean    @ConfigurationProperties(prefix = "jms")    public JmsMessageGatewayProperties messageGatewayProperties() {        return new JmsMessageGatewayProperties();    }}

这种方式确保了camel.properties中的属性在JmsMessageGatewayConnectionConfig被处理时已经存在于Spring的Environment中,从而允许@ConfigurationProperties正确绑定。

更新后的测试类(无需修改)无论选择哪种@PropertySource的放置方式,原始的测试类通常无需修改,因为它已经通过@TestPropertySource将属性加载到测试环境的Environment中。但为了确保@ConfigurationProperties的绑定机制能够感知到这些属性,上述@PropertySource的添加是关键。

方案二:利用Spring Boot的@ConfigurationPropertiesScan

如果你正在使用Spring Boot,并且版本较新(Spring Boot 2.2+),可以使用@ConfigurationPropertiesScan来简化@ConfigurationProperties的注册和绑定过程。

首先,JmsMessageGatewayProperties类不再需要@PropertySource注解,但需要确保它是一个Bean或者被Spring组件扫描到:

// JmsMessageGatewayProperties.java// 移除 @PropertySource// 可以添加 @Component 或通过 @EnableConfigurationProperties 注册public class JmsMessageGatewayProperties {    // ... 属性及Getter/Setter}

然后,在你的主应用类或测试配置类上添加@ConfigurationPropertiesScan:

// 例如,在测试配置类上@RunWith(SpringRunner.class)@ContextConfiguration(classes = { JmsMessageGatewayConnectionConfig.class})@TestPropertySource(locations = "classpath:camel.properties")@ConfigurationPropertiesScan // 添加此行public class JmsMessageGatewayConnectionConfigTest {    // ... 测试代码}

或者,如果JmsMessageGatewayProperties是通过@EnableConfigurationProperties注册的,@ConfigurationPropertiesScan会扫描到它:

@Configuration@EnableConfigurationProperties(JmsMessageGatewayProperties.class) // 显式注册public class JmsMessageGatewayConnectionConfig {    // ...    // 可以移除 @Bean 和 @ConfigurationProperties(prefix = "jms") 的方法,    // 因为 @EnableConfigurationProperties 会自动处理}

@ConfigurationPropertiesScan会自动扫描带有@ConfigurationProperties注解的类,并将其注册为Spring Bean,同时尝试绑定属性。这在Spring Boot应用中是推荐的现代化做法。

方案三:理解@DependsOn(通常不适用于属性绑定)

在原始问题中提到了@DependsOn,它允许你定义一个Bean在另一个Bean被创建之后才被创建。

@Bean@DependsOn("messageGatewayProperties") // 假设messageGatewayProperties是JmsMessageGatewayProperties Bean的名称public JmsMessageGatewayConnection jmsMessageGatewayConnection (final JmsMessageGatewayProperties jmsConfig) throws JMSException {    return new JmsMessageGatewayConnection(jmsConfig, cachingConnectionFactory(jmsConfig));}

虽然@DependsOn可以确保JmsMessageGatewayProperties Bean在JmsMessageGatewayConnection之前被创建,但它并不能解决属性绑定本身的问题。如果JmsMessageGatewayProperties的属性在创建时就是null,那么即使它先被创建,其内部属性仍然是null。@DependsOn主要用于解决Bean之间的初始化顺序依赖,而不是属性加载问题。因此,对于本场景,它不是一个直接有效的解决方案。

注意事项与最佳实践

Spring Boot vs. 纯Spring框架:Spring Boot: 提供了@ConfigurationPropertiesScan和@EnableConfigurationProperties等便利机制,简化了属性绑定。通常推荐在@ConfigurationProperties类上不加@PropertySource,而是通过application.properties/application.yml或@ConfigurationPropertiesScan来统一管理。纯Spring: 需要更明确地使用@PropertySource来指定属性文件,确保属性加载到Environment中。@TestPropertySource的作用: TestPropertySource主要用于在测试环境中覆盖或添加属性到Spring的Environment。它本身不会自动触发@ConfigurationProperties的绑定,需要配合@PropertySource或@ConfigurationPropertiesScan等机制。调试技巧: 如果属性仍然为null,可以在JmsMessageGatewayProperties的构造函数或setter方法上设置断点,检查属性值在何时何地被赋值。同时,可以检查Spring的Environment中是否包含预期的属性(例如,通过@Autowired Environment env并打印env.getProperty(“jms.remoteUri”))。属性文件命名: 确保@PropertySource或@TestPropertySource中指定的属性文件路径和名称是正确的。classpath:前缀表示从类路径加载。

总结

为Spring @Configuration类及其依赖的@ConfigurationProperties编写单元测试时,确保外部属性能够正确绑定是关键。核心在于让Spring容器知道去哪里找到这些属性,并激活@ConfigurationProperties的绑定机制。

对于纯Spring应用或需要明确指定属性文件的场景,在@ConfigurationProperties类或其配置类上使用@PropertySource 是最常见且有效的解决方案。对于Spring Boot应用,@ConfigurationPropertiesScan 提供了一种更自动化、更简洁的方式来管理和绑定配置属性。@DependsOn主要解决Bean创建顺序问题,不能直接解决属性绑定问题。

通过理解这些机制并选择合适的策略,开发者可以构建出健壮且易于维护的Spring配置单元测试。

以上就是Spring配置类与外部属性单元测试实践指南的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/332349.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
telnet不通linux中的tomcat端口
上一篇 2026年11月5日 19:03:07
客户满意度属于什么管理
下一篇 2025年11月16日 13:08:03

相关推荐

  • Java:从字符串中提取非ASCII字符并替换为ASCII字符

    Java:从字符串中提取非ASCII字符并替换为ASCII字符Java:从字符串中提取非ASCII字符并替换为ASCII字符Java:从字符串中提取非ASCII字符并替换为ASCII字符Java:从字符串中提取非ASCII字符并替换为ASCII字符

    本文旨在提供一种使用Java从字符串中提取非ASCII字符,并将其替换为对应的ASCII字符的有效方法。我们将通过示例代码演示如何使用replaceAll方法和HashMap来实现此功能,并提供完整的代码示例,帮助开发者快速解决类似问题。 在处理包含非ASCII字符的文本数据时,我们常常需要将其转换…

    2026年11月5日 • 用户投稿
    000
  • 如何在抖音平台以外沉淀用户并构建私域流量?

    如何在抖音平台以外沉淀用户并构建私域流量?如何在抖音平台以外沉淀用户并构建私域流量?如何在抖音平台以外沉淀用户并构建私域流量?如何在抖音平台以外沉淀用户并构建私域流量?

    在抖音之外实现用户沉淀与私域流量建设,关键在于借助微信公众号、企业微信、小程序及社群等多种渠道,推动用户深度互动与长期运营。这些方式有助于品牌打造稳固的用户关系链,增强用户黏性,并最终完成私域流量的高效转化。 借力微信公众号实现用户留存 作为主流的内容传播平台,微信公众号为品牌提供了与用户持续沟通的…

    2026年11月5日 • 用户投稿
    100
  • 《彩虹主题壁纸》搜索壁纸方法

    《彩虹主题壁纸》搜索壁纸方法《彩虹主题壁纸》搜索壁纸方法《彩虹主题壁纸》搜索壁纸方法《彩虹主题壁纸》搜索壁纸方法

    打开彩虹主题壁纸APP后,进入首页可以看到顶部有一个带放大镜图标的搜索栏。 点击搜索框,输入你想查找的壁纸关键词,例如“极光”、“卡通”或“抽象”等,即可快速查找相关内容。 壁纸样机神器 免费壁纸样机生成 0 查看详情 搜索结果会即时呈现大量高清壁纸,用户可上下滑动浏览,选中喜欢的图片后支持一键下载…

    2026年11月5日 • 用户投稿
    000
  • Java:从包含非ASCII字符的字符串中提取并替换特定字符

    Java:从包含非ASCII字符的字符串中提取并替换特定字符Java:从包含非ASCII字符的字符串中提取并替换特定字符Java:从包含非ASCII字符的字符串中提取并替换特定字符Java:从包含非ASCII字符的字符串中提取并替换特定字符

    本文将介绍如何在Java中处理包含非ASCII字符的字符串,并提供使用replaceAll()方法和HashMap进行字符替换的详细示例。通过本文,你将学习如何读取文件,识别包含非ASCII字符的行,并将这些字符替换为ASCII字符,从而解决在处理文本数据时可能遇到的编码问题。 在处理文本文件时,经…

    2026年11月5日 • 用户投稿
    000
  • 【教程帖】鸿蒙版微信收不到消息?简单几步搞定难题!

    【教程帖】鸿蒙版微信收不到消息?简单几步搞定难题!【教程帖】鸿蒙版微信收不到消息?简单几步搞定难题!【教程帖】鸿蒙版微信收不到消息?简单几步搞定难题!【教程帖】鸿蒙版微信收不到消息?简单几步搞定难题!

    期盼已久的国庆中秋小长假终于要来了!无论是约上好友尽情玩耍,还是与家人视频通话叙亲情,又或是在群里抢红包热闹一番,微信都必不可少。假期期间聊天是否顺畅,全靠它来保障!不过最近,一些使用鸿蒙版微信的用户反映“收不到消息提醒”,其实问题很可能出在系统设置还没调对——别急,最全解决方案来了,轻松帮你解决通…

    2026年11月5日 • 用户投稿
    000
  • GraalVM 将重点转向 Python/JavaScript 等非 Java 语言

    GraalVM 将重点转向 Python/JavaScript 等非 Java 语言GraalVM 将重点转向 Python/JavaScript 等非 Java 语言GraalVM 将重点转向 Python/JavaScript 等非 Java 语言GraalVM 将重点转向 Python/JavaScript 等非 Java 语言

    继 2022 年宣布将 graalvm ce 中的 java 代码贡献给 openjdk 后,oracle 近日再次发布声明,明确 graalvm 未来的发展方向将聚焦于非 java 语言生态。 关于 GraalVM 与 Java SE 相关的产品路线图,主要更新内容如下: GraalVM 团队正进…

    2026年11月5日 • 用户投稿
    100
  • Stable Diffusion出图慢?显卡设置优化与加速技巧

    Stable Diffusion出图慢?显卡设置优化与加速技巧Stable Diffusion出图慢?显卡设置优化与加速技巧Stable Diffusion出图慢?显卡设置优化与加速技巧Stable Diffusion出图慢?显卡设置优化与加速技巧

    stable diffusion出图慢的解决方法包括检查并更新显卡驱动、优化webui设置(启用xformers、调整batch count和batch size)、合理使用vae参数、选择适当优化选项(如–opt-split-attention)、谨慎超频显卡、降低分辨率、简化提示词,…

    2026年11月5日 • 用户投稿
    000
  • 秘读小说如何删书架图书

    秘读小说如何删书架图书秘读小说如何删书架图书秘读小说如何删书架图书秘读小说如何删书架图书

    在秘读小说app中,想要清理书架上的书籍,只需长按目标图书,系统便会弹出删除提示,确认后即可成功移除。 1、 首先打开手机中的秘读小说软件,进入个人书架界面后点击相应功能按钮。 2、 在跳转的页面中选择“书架管理”功能入口。 标小兔AI写标书 一款专业的标书AI代写平台,提供专业AI标书代写服务,安…

    2026年11月5日 • 用户投稿
    000
  • 俄罗斯Yandex搜索免登录通道 Yandex引擎无需注册入口

    俄罗斯Yandex搜索免登录通道为https://yandex.com/,用户无需注册或登录即可使用网页、图片、新闻等核心搜索功能,支持多语言切换与跨设备访问。 1、立即进入“俄罗斯yandex搜索免登录通道☜☜☜☜☜点击进入”; 2、立即进入“Yandex引擎无需注册入口☜☜☜☜☜点击进入”; 俄…

    2026年11月5日
    000
  • Java:处理非ASCII字符,替换为ASCII字符的实用指南

    Java:处理非ASCII字符,替换为ASCII字符的实用指南Java:处理非ASCII字符,替换为ASCII字符的实用指南Java:处理非ASCII字符,替换为ASCII字符的实用指南Java:处理非ASCII字符,替换为ASCII字符的实用指南

    本文旨在帮助Java开发者处理包含非ASCII字符的字符串,并将其替换为对应的ASCII字符。我们将通过示例代码,详细讲解如何使用replaceAll方法和HashMap来实现字符替换,并提供完整的可运行示例,帮助读者快速掌握该技巧。 在处理文本数据时,我们经常会遇到包含非ASCII字符的情况。例如…

    2026年11月5日 • 用户投稿
    000
  • Java中非ASCII字符的高效处理与替换策略

    Java中非ASCII字符的高效处理与替换策略Java中非ASCII字符的高效处理与替换策略Java中非ASCII字符的高效处理与替换策略Java中非ASCII字符的高效处理与替换策略

    本文详细介绍了在Java中如何高效地识别并替换文本文件中的非ASCII字符。通过利用String.replaceAll()方法结合哈希映射表(HashMap),可以实现灵活且系统化的字符替换,将特定非ASCII字符转换为对应的ASCII字符,从而解决文本数据处理中常见的字符编码兼容性问题,确保数据清…

    2026年11月5日 • 用户投稿
    300
  • 抖音团购券能做什么?功能与用途详细解析

    抖音团购券能做什么?功能与用途详细解析抖音团购券能做什么?功能与用途详细解析抖音团购券能做什么?功能与用途详细解析抖音团购券能做什么?功能与用途详细解析

    抖音团购券的核心功能解析 抖音团购券最核心的价值在于为线下门店实现线上引流与即时转化。用户在浏览短视频或直播时,可直接下单购买团购券,并在到店后完成核销,形成“内容触达—下单购买—线下消费”的完整链路。商家可通过团购券设置**组合套餐、限时抢购、单店专属优惠**等多种营销形式,灵活制定促销策略,尤其…

    2026年11月5日 • 用户投稿
    400
  • PowerShell 脚本在命令行工作,但在 Java 代码中不工作?

    PowerShell 脚本在命令行工作,但在 Java 代码中不工作?PowerShell 脚本在命令行工作,但在 Java 代码中不工作?PowerShell 脚本在命令行工作,但在 Java 代码中不工作?PowerShell 脚本在命令行工作,但在 Java 代码中不工作?

    本文旨在解决 PowerShell 脚本在命令行环境下成功执行,但在 Java 代码中调用时却无法正常工作的问题。通过分析 Java 代码中调用 PowerShell 脚本的方式,以及 PowerShell 命令行参数的传递规则,提供一种正确的解决方案,确保脚本在 Java 环境中也能顺利执行。本文…

    2026年11月5日 • 用户投稿
    000
  • 抽象类在Java中是否可以实现接口

    抽象类可以实现接口,使用implements关键字,无需实现所有方法,子类继承时再完成具体实现。例如Flyable接口含fly(),抽象类Animal实现该接口但不实现fly(),Bird类继承Animal并实现fly()。这种机制兼顾%ignore_a_1%与契约定义,广泛用于框架设计。 可以,抽…

    2026年11月5日
    000
  • 使用 Mock 进行单元测试的正确姿势

    使用 Mock 进行单元测试的正确姿势使用 Mock 进行单元测试的正确姿势使用 Mock 进行单元测试的正确姿势使用 Mock 进行单元测试的正确姿势

    本文旨在帮助初学者理解如何在单元测试中使用 Mock,特别是针对涉及第三方 API 调用和文件写入的场景。通过 WireMock 示例,展示了如何模拟不同响应码和响应体,以及如何验证请求头和 URL,从而编写更有效的单元测试。 单元测试中的 Mock 策略 在编写单元测试时,一个常见的挑战是如何处理…

    2026年11月5日 • 用户投稿
    000
  • bmi体重计算器入口

    bmi体重计算器入口bmi体重计算器入口bmi体重计算器入口bmi体重计算器入口

    bmi体重计算器入口: 网址链接:www.bmi.com.cn 手机App:点此下载 BMI体重指数计算器在线使用极为方便,只需打开指定网页或应用入口,输入身高与体重数据,系统便会按照公式 BMI=体重(kg)/身高(m)² 自动计算出对应的BMI数值,并提供健康状态分析。这种即时查询方式操作简单、…

    2026年11月5日 • 用户投稿
    200
  • 苹果手机如何删除多余人脸认证

    一、打开面容ID设置页面 要管理或删除已录入的人脸信息,首先需要进入系统中的面容ID设置区域。该功能位于“设置”应用中的“面容ID与密码”选项内。 1. 启动“设置”应用:在手机主屏上找到“设置”图标并点击进入。 2. 进入面容ID管理界面:在设置菜单中向下滚动,选择“面容ID与密码”。若尚未设置锁…

    2026年11月5日
    000
  • 抖音有赞商城订单查看步骤详解

    抖音有赞商城订单查看步骤详解抖音有赞商城订单查看步骤详解抖音有赞商城订单查看步骤详解抖音有赞商城订单查看步骤详解

    抖音有赞商城订单查询操作指南 作为国内领先的短视频社交平台,抖音不仅提供丰富的娱乐内容,还融合了多种电商服务。其中,有赞商城因其便捷的购物体验,受到众多消费者的青睐。不少用户在完成购买后,想要了解如何查看订单信息。下面将为你详细介绍具体的操作流程。 一、登录个人抖音账户 第一步是确保你已成功登录抖音…

    2026年11月5日 • 用户投稿
    000
  • 如何高效构建Web应用端到端测试?Behatch与Composer助你事半功倍!

    最近在开发一个复杂的Web应用时,团队面临着一个巨大的挑战:如何确保每次迭代都能快速、可靠地进行回归测试。随着功能模块的不断增加,手动测试已经成为一个瓶颈,不仅耗时耗力,还容易遗漏问题。我们决定引入自动化端到端测试,选择了Behat作为我们的BDD(行为驱动开发)测试框架。然而,刚开始就碰到了一个难…

    2026年11月5日
    000
  • Jackson反序列化Java Record的常见陷阱与版本兼容性解决方案

    Jackson反序列化Java Record的常见陷阱与版本兼容性解决方案Jackson反序列化Java Record的常见陷阱与版本兼容性解决方案Jackson反序列化Java Record的常见陷阱与版本兼容性解决方案Jackson反序列化Java Record的常见陷阱与版本兼容性解决方案

    本文深入探讨了Jackson在反序列化Java Record时可能遇到的InvalidDefinitionException问题。尽管Jackson 2.12.x及更高版本已原生支持Record,但由于潜在的Jackson版本冲突,开发者常被迫冗余地使用@JsonProperty注解。文章揭示了这一…

    2026年11月5日 • 用户投稿
    000

发表回复

登录后才能评论
关注微信