使用Profile和Resources Filter隔离测试环境

本文介绍了一个30人跨国团队在使用Maven进行项目管理和测试时遇到的问题及解决方案。通过使用Profile和Maven Resources插件,实现了不同环境下的个性化配置。
部署运行你感兴趣的模型镜像

Maven能够帮我们很好的管理测试,我们可以在 src/test/java src/test/resources 下面使用JUnit或者TestNG 编写单元测试和集成测试,然后在命令行运行 mvn test ,测试就会自动运行,同时产生详细的测试报告。对只有一两个人的项目来说,不会碰到本文将提到的问题。

 

我们考虑以下场景(这也是我在实际项目中碰到的问题):有一个大概30人团队的项目,其中一半在美国,另一半在中国,要知道两个地方的网络连接速度不是很快,也就是说从地球的一端连接地球另一端的数据库十分耗时。中国的团队开发了一些模块,也很积极的编写了大量单元测试和集成测试(我这里说的单元测试使指不对外部任何环境有依赖),这些代码完全由Maven管理,所以在中国团队这里,持续集成服务器上只有简单的一条 mvn clean install 命令,一切都很好!但是,当美国团队签出同样的源代码,运行同样的命令时,问题出现了,测试在他们那里总是过不去,经过检查,发现代码中有太多的硬编码的数据库链接,以及其它的对外部环境的依赖。于是他们抱怨:How can you hardcode database link? 中国的同事很委屈:我们已经从代码里把这些东西抽取到配置文件里了,这不算Hardcode吧。大家暂时没办法,于是只能在build命令后加上-Dtest -DfailIfNoTests ,build可以过了,但是美国团队心里总是不舒服,尤其是当他们代码把测试弄坏时,他们经常不知道。

 

问题总是要解决的,更何况现在的问题也不小。让我们看看Maven为我们提供了什么,大家首先会想到的肯定是Profile,通过Profile,我们可以通过Maven传入一些个性化变量。考虑一下我们的情况下什么需要个性化?也就是说什么东西在不同的地方值是不一样的?答案是src/test/resources 下的一些资源文件,如JPA用到的 persistence.xml ,其中包含了这样的内容:

 

    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>

    <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/>

    <property name="hibernate.connection.username" value="test"/>

    <property name="hibernate.connection.password" value="test"/>

 


我们看到这个资源文件绑定到了本机的mysql数据库上,我们需要从Maven传入这些参数,包括url, username和password。可问题是,通过Profile传输的个性化变量,我们能在pom.xml里面引用,我们如何在src/test /resources 下的资源文件里引用它们呢?


先别急,先让我们把Profile定义好,这里我选择在%M2_HOME%/conf 下的settings.xml 里定义全局的Profile,因为数据库链接是很多模块的测试都会用到的,定义如下:

 

<profiles>

  <profile>

    <id>myProfile</id>

    <properties>

      <mysql.url>jdbc:mysql://localhost:3306</mysql.url>

      <mysql.username>test</mysql.username>

      <mysql.password>test</mysql.password>

      <mysql.dbname>test</mysql.dbname>

    </properties>

  </profile>

</profiles>

<activeProfiles>

  <activeProfile>myProfile</activeProfile>

</activeProfiles>

 

此外,修改资源文件如下:

 

    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>

    <property name="hibernate.connection.url" value="jdbc:mysql://${mysql.url}/${mysql.dbname}"/>

    <property name="hibernate.connection.username" value="${mysql.username}"/>

    <property name="hibernate.connection.password" value="${mysql.password}"/>

 

至此,我们已经把环境相关的变量隔离开了,每个用户都有自己的settings.xml 文件,所以每个人都能配置自己的settings.xml 来使用他想要使用的数据库。针对我们上面的场景,美国的团队只要在本地配置一个数据库,他们也就可以运行测试了,皆大欢喜!

 

最后,不要忘了配置 Maven Resources 插件让它开启 filtering 功能:

 

      [...]
      <resource>
        <directory>src/test/resources</directory>
        <filtering>true</filtering>
      </resource>
      [...]
 

至此,运行 mvn install ,Maven 会让 Resources 插件首先根据 setttings.xml 文件中的值填充测试资源文件中的变量,然后再运行测试。这种解决方案不仅仅适用于数据库,任何外部环境配置都可以使用该方案,如对消息服务器的依赖。尽情享受Maven给你带来的便利吧!

 

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们面对的问题:在单元测试中如何避免加载Spring Cloud相关组件(特别是Feign相关配置) 用户需求:在使用Spring Cloud Netflix Feign的应用中,配置单元测试环境以排除Spring Cloud相关组件的加载 分析: 1. Feign是Spring Cloud生态中用于服务间调用的组件,在单元测试中我们通常不希望启动整个Spring Cloud环境(如服务发现、负载均衡等) 2. 单元测试应尽可能快速且独立,因此需要避免加载与当前测试无关的组件 解决方案: 我们可以通过多种方式在测试中排除Spring Cloud自动配置,特别是Feign的自动配置。以下提供几种常用方法: 方法一:使用@TestConfiguration@EnableAutoConfiguration(exclude)排除自动配置类 这是最直接的方式,我们可以创建一个测试专用的配置类,排除Feign相关的自动配置。 步骤: 1. 创建测试配置类,使用@EnableAutoConfiguration(exclude)排除FeignAutoConfiguration等 2. 在测试类上使用@Import导入这个测试配置 示例代码: ```java @SpringBootTest @Import(TestConfigWithoutFeign.class) public class MyServiceTest { // 测试方法 } @TestConfiguration @EnableAutoConfiguration(exclude = { FeignAutoConfiguration.class, // 排除Feign自动配置 RibbonAutoConfiguration.class, // 排除Ribbon(Feign依赖Ribbon) LoadBalancerAutoConfiguration.class // 排除负载均衡 // 其他需要排除的Spring Cloud自动配置类 }) public class TestConfigWithoutFeign { // 如果需要,可以手动创建一些测试所需的Bean,比如Mock的Feign客户端 // 例如,如果测试的类中注入了某个Feign客户端,我们可以在这里提供一个MockBean @Bean @Primary public SomeFeignClient someFeignClient() { return Mockito.mock(SomeFeignClient.class); } } ``` 方法二:使用@ActiveProfilesProfile-specific配置 我们可以通过Profile来控制配置的加载。在测试环境下,激活一个特定的Profile,然后在该Profile的配置中排除Feign的自动配置。 步骤: 1. 在主配置类上使用@Profile注解,确保Feign的配置只在非测试环境下生效 2. 在测试类上激活测试Profile 示例: 主配置类(通常配置Feign): ```java @Configuration @Profile("!test") // 只在非测试环境生效 @EnableFeignClients public class FeignConfig { } ``` 测试类: ```java @SpringBootTest @ActiveProfiles("test") // 激活test profile,这样FeignConfig就不会被加载 public class MyServiceTest { // 测试方法 } ``` 方法三:在测试配置文件中禁用相关配置 在测试资源目录下的application.properties或application.yml中,我们可以设置属性来禁用Feign相关的自动配置。 示例(application-test.properties): ```properties spring.cloud.openfeign.enabled=false spring.cloud.loadbalancer.ribbon.enabled=false # 如果需要,也可以禁用服务发现 spring.cloud.discovery.enabled=false ``` 然后在测试类上激活test profile(同上方法二)。 方法四:使用MockBean模拟Feign客户端 如果我们只是不希望Feign客户端去进行远程调用,而是希望用Mock代替,那么可以使用@MockBean来模拟Feign客户端接口。 示例: ```java @SpringBootTest public class MyServiceTest { @Autowired private MyService myService; @MockBean private SomeFeignClient someFeignClient; // 这个Feign客户端会被Mockito的mock代替 @Test public void testMethod() { Mockito.when(someFeignClient.someMethod()).thenReturn("mock result"); // 然后调用myService的方法,它会使用mock的Feign客户端 } } ``` 这种方法不需要排除自动配置,而是用Mock对象替换掉实际的Feign客户端,这样就不会进行真实的远程调用,同时测试速度也很快。 方法五:使用@SpringBootTest的properties属性 在测试类上直接通过properties属性设置,禁用Feign: ```java @SpringBootTest(properties = { "spring.cloud.openfeign.enabled=false", "spring.cloud.discovery.enabled=false" }) public class MyServiceTest { // ... } ``` 根据引用[5]中提到的错误,有时候在测试中排除不彻底会导致一些奇怪的错误,所以我们需要确保排除完整。 推荐方法: 1. 如果测试中完全不需要Feign,建议使用方法一或方法五,直接排除自动配置类,这样最彻底。 2. 如果测试中需要用到Feign客户端,但是希望Mock它的行为,那么使用方法四(@MockBean)是最方便的。 注意事项: 1. 在排除配置时,注意Spring Cloud版本问题(如引用[3][4]提到的版本匹配问题),不同版本的自动配置类名可能不同。 2. 如果使用排除自动配置类的方式,需要知道哪些自动配置类需要排除。通常需要排除的包括: - FeignAutoConfiguration - RibbonAutoConfiguration - LoadBalancerAutoConfiguration - DiscoveryClient相关的配置(如EurekaClientAutoConfiguration等,如果使用了服务发现) 3. 如果测试中出现了与Feign或负载均衡相关的错误,请检查是否排除完整。 验证排除是否成功: 可以在测试中尝试从应用上下文中获取Feign相关的Bean,如果排除成功,应该获取不到。 示例验证: ```java @SpringBootTest @Import(TestConfigWithoutFeign.class) public class MyServiceTest { @Autowired private ApplicationContext context; @Test public void testFeignBeanNotLoaded() { // 尝试获取FeignClient的Bean,应该抛出异常 assertThrows(NoSuchBeanDefinitionException.class, () -> context.getBean(SomeFeignClient.class)); } } ``` 相关问题: 1. 如何在Spring Boot测试中排除特定的自动配置类? 2. 如何为Feign客户端编写Mock测试? 3. Spring Cloud不同版本中Feign的自动配置类名有什么变化? 4. 在单元测试中禁用Spring Cloud服务发现有哪些方法? 5. 使用@MockBean模拟Feign客户端时遇到NullPointerException如何解决?</think>### 在 Spring Cloud Feign 应用中配置单测环境排除 Spring Cloud 组件 以下是针对使用 `org.springframework.cloud.netflix.feign` 的应用服务,配置单元测试环境避免加载 Spring Cloud 组件的完整方案: #### 方案一:测试配置类排除法(推荐) ```java @SpringBootTest @Import(FeignTestConfig.class) // 导入专用测试配置 public class OrderServiceTest { // 测试用例 } @TestConfiguration @EnableAutoConfiguration(exclude = { FeignAutoConfiguration.class, // 排除Feign核心配置[^1][^3] RibbonAutoConfiguration.class, // 排除负载均衡 DiscoveryClientAutoConfiguration.class // 排除服务发现 }) public class FeignTestConfig { // 模拟Feign客户端接口 @MockBean @Primary // 优先使用Mock对象 private ProviderService providerService; // 引用[2]中的FeignClient接口 // 提供基础RestTemplate @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } ``` **关键点**: 1. `@EnableAutoConfiguration(exclude)` 显式排除 Feign 核心配置[^1][^3] 2. `@MockBean` 模拟 Feign 客户端接口[^2] 3. 手动提供基础 HTTP 组件(如 `RestTemplate`) #### 方案二:配置文件禁用方案 ```properties # src/test/resources/application.properties spring.cloud.openfeign.enabled=false # 禁用Feign自动配置[^3] spring.cloud.discovery.enabled=false # 禁用服务发现 spring.main.allow-bean-definition-overriding=true # 允许Bean覆盖 ``` #### 方案三:条件化Bean注册 ```java @Configuration public class ConditionalFeignConfig { @Bean @ConditionalOnMissingBean(TestContext.class) // 仅非测试环境注册 public FeignContext feignContext() { return new FeignContext(); } } // 测试类添加标记 @SpringBootTest @TestConfiguration public class OrderServiceTest { @Bean public TestContext testContextMarker() { return new TestContext(); // 阻止FeignContext注册 } } ``` #### 验证排除效果 ```java @Test public void shouldNotLoadFeignComponents() { // 验证Feign核心Bean不存在 assertThrows(NoSuchBeanDefinitionException.class, () -> context.getBean(FeignContext.class)); // 验证负载均衡组件不存在 assertThrows(NoSuchBeanDefinitionException.class, () -> context.getBean(LoadBalancerClient.class)); } ``` #### 常见问题解决 **问题:出现 `No qualifying bean of type 'org.springframework.cloud.openfeign...` 错误[^5]** ```java // 解决方案:显式提供空FeignBuilder @TestConfiguration public class EmptyFeignConfig { @Bean @Primary public Feign.Builder feignBuilder() { return Feign.builder(); // 提供空实现 } } ``` **问题:Feign 客户端接口被意外加载** ```java // 在测试配置类中添加 @ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = FeignClient.class) // 排除所有FeignClient ) ``` ### 版本兼容性注意 必须确保 Spring Cloud 与 Feign 版本匹配[^3][^4]: ```xml <!-- pom.xml 示例 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR5</version> <!-- 匹配版本 --> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.6.RELEASE</version> <!-- 兼容版本 --> </dependency> ``` ### 最佳实践总结 1. **隔离原则**:测试配置与生产配置物理分离 2. **精确排除**:显式排除 `FeignAutoConfiguration` 等核心自动配置类 3. **模拟替代**:使用 `@MockBean` 代替真实 Feign 客户端[^1] 4. **版本控制**:严格匹配 Spring Cloud OpenFeign 版本[^3][^4] 5. **分层验证**:添加 Bean 存在性断言确保排除生效 --- ### 相关问题 1. 如何为 Feign 客户端接口编写 Mock 测试用例? 2. 在禁用服务发现后如何手动配置服务端点? 3. 多模块项目中如何共享 Feign 测试配置?[^2] 4. Spring Cloud 2020 以后版本排除配置有何变化?[^3][^4] 5. 使用 Testcontainers 时如何避免与 Feign 冲突?[^5]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值