记一次Feign单元测试报错NoSuchBeanDefinitionException

背景

Springboot项目集成Feign,Ribbon(由于项目部署在K8S集群中,所以未使用Eureka),因此FeignClient使用url来调用其他服务,配置如下:

@FeignClient(name = "user", url = "${user.url}", configuration = {FeignExceptionDecoder.class})

此时url是的值是占位符,读取的配置文件,项目运行没有问题

问题

1. 执行单元测试时,BaseTest报错

无法初始化feignClient,因为占位符http://${user.url}替换不了

第一反应是配置文件读取失败,要不然占位符已经被成功替换了,而不是拼上http://,于是去检查配置,配置没有问题

很奇怪,于是去看EnableFeignClients注解,点到FeignClientsRegistrar.Class,搜索url发现了getUrl()方法(如下),看到里面用的是#{}而不是${}去判断,于是突发奇想,把所有的FeignClient里的url都使用#{},执行单元测试,不报这个错了

static String getUrl(String url) {
    if (StringUtils.hasText(url) && (!url.startsWith("#{") || !url.contains("}"))) {
        if (!url.contains("://")) {
            url = "http://" + url;
        }

        try {
            new URL(url);
        } catch (MalformedURLException var2) {
            throw new IllegalArgumentException(url + " is malformed", var2);
        }
    }

    return url;
}

2. 继续执行单元测试,抛出异常NoSuchBeanDefinitionException

如果在此时运行项目,会发现FeignClient的bean都无法注入了,但是当时博主已被自己的机智迷昏了头脑,没发现这个问题

这时候,网上各种搜索这个报错,发现看下来有以下几个解决方法:

  • BaseTest启动类加上注解
@EnableFeignClients

但是博主已经加了的,所以这个对博主无用

  • BaseTest启动类加上注解
@ImportAutoConfiguration({RibbonAutoConfiguration.class, FeignRibbonClientAutoConfiguration.class, FeignAutoConfiguration.class})

加上试了无用,还是一样的报错

  • BaseTest启动类加上注解
@EnableFeignClients(basePackages = "com.xxx")

刚试完加上单元测试还是报错,突然发现项目跑不起来了,而且代码是push过的(因为让另一个同事帮忙一起看下),此时博主开始慌了,赶紧把FeignClient里url的占位符#再改回$,项目跑起来了,谢天谢地。

这时候博主突然奇想,会不会是因为配置的basePackages范围太大了(博主的项目是多模块分层的,所有的FeignClient都放在Service模块的第x层包下,而此时就只配到第2层而已),所以修改basePackages,配置到FeignClient所在的包目录

惊奇的发现!单元测试跑起来了!依赖注入也都有值

总结

其实最开始的占位符http://${user.url}替换不了,以及后面的NoSuchBeanDefinitionException,都应该想到,是因为springboot扫包没扫到引起的,贴上博主可行的配置

@RunWith(SpringRunner.class)
@SpringBootTest
@EnableFeignClients(basePackages = "com.xxxx.xxxx.xxxx.xxxx")
public class BaseTest extends AbstractTransactionalTestNGSpringContextTests {
}

收工!

你可能感兴趣的:(记一次Feign单元测试报错NoSuchBeanDefinitionException)