使用 @Configuration bean 覆盖 @FeignClient 进行测试
Override @FeignClient using a @Configuration bean for tests
是否可以通过创建一个包含用于测试的模拟版本的 @Configuration
bean 来覆盖通过 @FeignClient
注释创建的 bean?
我已经尝试过了,但似乎 @FeignClient
bean 是最后创建的(或者我认为如此),因为在我的测试中我总是注入真实版本而不是模拟版本。在同一个配置文件中,我创建了另一个没有任何注释的 bean(@Component
除外),仅使用真实的名称以相同的方式进行模拟,并且效果很好。
我试过使用 @MockBean
来模拟它并且它有效,但该项目有一些怪癖,使得另一个 Spring 上下文的创建中断了测试。
谢谢。
编辑。实际上,我刚刚调试了测试并意识到,如果我使用与 Feign 客户端相同的名称,调试器甚至不会在 @Configuration
bean 中停止以创建模拟版本。将名称更改为其他名称可以工作,但它只会创建另一个具有新名称的相同类型的 bean。我在这里缺少任何配置吗?
编辑 2. 这是一个示例代码。执行这个我有 BarService
是模拟版本,但 FooService
是真实版本。
@FeignClient(name = "fooService")
public interface FooService {
}
@Component
public class BarService {
}
@Configuration
public class ConfigClass {
@Bean
public FooService fooService() {
return Mockito.mock(FooService.class);
}
@Bean
public BarService barService() {
return Mockito.mock(BarService.class);
}
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
public class TestClass {
@Autowired
private FooService fooService;
@Autowired
private BarService barService;
@Test
public void test() {
System.out.println(fooService.getClass());
}
}
如果你能分享你的测试就太好了class。
据我了解,您的问题是您需要在测试中覆盖一个 bean。
具体操作可以参考以下问题:
你的问题是由于 FeignClient bean 被定义为 primary
就像用 @Primary
声明一个 bean 一样。所以它比其他普通 bean 有优先权。
从 Dalston 版本中包含的 spring-cloud-netflix 1.3.0,您可以关闭此主要配置,如下所示。
@FeignClient(name = "fooService", primary = false)
public interface FooService {
}
如果您像上面那样更改代码,模拟 bean 将被注入到您的测试中。
您需要注意的一件事是,当您为 FeignClient 使用后备 bean 时,会使用 primary
选项。如果你有后备 bean,你可能需要用 qualifer 指定 FeignClient bean 来让 FeignClient bean 超过后备 bean。
我认为另一种为测试注入模拟 bean 而不是 FeignClient bean 的方法是使用 BeanPostProcessor
类似下面的东西。
public static class MockProcessor implements BeanPostProcessor {
:
:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (/* distinguish your target bean */)
return Mockito.mock(FooService.class);
return bean;
}
}
注解@EnableFeignClients
默认会为标有@FeignClient
的接口创建主bean。为每个接口禁用此功能可能会产生副作用,例如存在回退 bean 时。
为了首先防止创建 Feign bean,只需将此注释移动到已禁用测试的配置 class。
@Configuration
@Profile("!test")
@EnableFeignClients
public class FeignEnable {
}
然后用 @ActiveProfiles("test")
.
注释你的测试 class
是否可以通过创建一个包含用于测试的模拟版本的 @Configuration
bean 来覆盖通过 @FeignClient
注释创建的 bean?
我已经尝试过了,但似乎 @FeignClient
bean 是最后创建的(或者我认为如此),因为在我的测试中我总是注入真实版本而不是模拟版本。在同一个配置文件中,我创建了另一个没有任何注释的 bean(@Component
除外),仅使用真实的名称以相同的方式进行模拟,并且效果很好。
我试过使用 @MockBean
来模拟它并且它有效,但该项目有一些怪癖,使得另一个 Spring 上下文的创建中断了测试。
谢谢。
编辑。实际上,我刚刚调试了测试并意识到,如果我使用与 Feign 客户端相同的名称,调试器甚至不会在 @Configuration
bean 中停止以创建模拟版本。将名称更改为其他名称可以工作,但它只会创建另一个具有新名称的相同类型的 bean。我在这里缺少任何配置吗?
编辑 2. 这是一个示例代码。执行这个我有 BarService
是模拟版本,但 FooService
是真实版本。
@FeignClient(name = "fooService")
public interface FooService {
}
@Component
public class BarService {
}
@Configuration
public class ConfigClass {
@Bean
public FooService fooService() {
return Mockito.mock(FooService.class);
}
@Bean
public BarService barService() {
return Mockito.mock(BarService.class);
}
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
public class TestClass {
@Autowired
private FooService fooService;
@Autowired
private BarService barService;
@Test
public void test() {
System.out.println(fooService.getClass());
}
}
如果你能分享你的测试就太好了class。
据我了解,您的问题是您需要在测试中覆盖一个 bean。
具体操作可以参考以下问题:
你的问题是由于 FeignClient bean 被定义为 primary
就像用 @Primary
声明一个 bean 一样。所以它比其他普通 bean 有优先权。
从 Dalston 版本中包含的 spring-cloud-netflix 1.3.0,您可以关闭此主要配置,如下所示。
@FeignClient(name = "fooService", primary = false)
public interface FooService {
}
如果您像上面那样更改代码,模拟 bean 将被注入到您的测试中。
您需要注意的一件事是,当您为 FeignClient 使用后备 bean 时,会使用 primary
选项。如果你有后备 bean,你可能需要用 qualifer 指定 FeignClient bean 来让 FeignClient bean 超过后备 bean。
我认为另一种为测试注入模拟 bean 而不是 FeignClient bean 的方法是使用 BeanPostProcessor
类似下面的东西。
public static class MockProcessor implements BeanPostProcessor {
:
:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (/* distinguish your target bean */)
return Mockito.mock(FooService.class);
return bean;
}
}
注解@EnableFeignClients
默认会为标有@FeignClient
的接口创建主bean。为每个接口禁用此功能可能会产生副作用,例如存在回退 bean 时。
为了首先防止创建 Feign bean,只需将此注释移动到已禁用测试的配置 class。
@Configuration
@Profile("!test")
@EnableFeignClients
public class FeignEnable {
}
然后用 @ActiveProfiles("test")
.