是否可以通过创建一个包含用于测试的模拟版本的 @Configuration
bean 来覆盖通过 @FeignClient
注解创建的 bean?
我已经尝试过了,但似乎 @FeignClient
bean 是最后创建的(或者我认为如此),因为在我的测试中,我总是注入(inject)真实版本而不是模拟版本。在同一个配置文件中,我创建了另一个没有任何注释的 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());
}
}
最佳答案
你的问题是由于 FeignClient bean 被定义为 primary
就像用 @Primary
声明一个 bean 一样。所以它比其他普通 bean 有优先权。
从 Dalston 版本中包含的 spring-cloud-netflix 1.3.0 开始,您可以关闭此主要配置,如下所示。
@FeignClient(name = "fooService", primary = false)
public interface FooService {
}
如果您像上面那样更改代码,模拟 bean 将被注入(inject)到您的测试中。
您需要注意的一件事是,当您为 FeignClient 使用后备 bean 时,会使用 primary
选项。如果你有后备 bean,你可能需要用 qualifer 指定 FeignClient bean 来让 FeignClient bean 超过后备 bean。
我认为另一种为测试注入(inject)模拟 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;
}
}
关于java - 使用 @Configuration bean 覆盖 @FeignClient 进行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44265928/