Home > Back-end >  How to autowire feign client (for external API) in a test?
How to autowire feign client (for external API) in a test?

Time:07-13

I've written a simple Feign client, for calling an external API (running on a different server):

@FeignClient(
        name = "test-service",
        url = "https://some-test-server.com/api"
)
public interface TestClient {

    @RequestMapping(method = RequestMethod.POST, value = "/test")
    TestResponse test(TestRequest request);
}

I wrote some simple bean classes, TestRequest & TestResponse to model the request / response - I'm expecting them to be serialized & deserialized as json.

I want to just test that its able to make the HTTP call and receive a response, so I wrote a test:

@SpringBootTest
@EnableFeignClients(clients = TestClient.class)
class ClientApplicationTests {

    @Autowired
    private TestClient client;

    @Test
    void contextLoads() {
        System.out.println(client.test(TestRequest.builder().foo("foo").build()));
    }

But Intellij warns me that no Beans were found to autowire TestClient, and running this gives a similar exception:

java.lang.NoClassDefFoundError: org/springframework/cloud/context/named/NamedContextFactory$Specification
    at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[na:na]
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012) ~[na:na]
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681) ~[na:na]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639) ~[na:na]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[na:na]
    at org.springframework.cloud.openfeign.FeignClientsRegistrar.registerClientConfiguration(FeignClientsRegistrar.java:410) ~[spring-cloud-openfeign-core-3.1.3.jar:3.1.3]

What am I doing wrong?

CodePudding user response:

Try giving your Feign client class name in this format and check whether this works,

@EnableFeignClients(basePackageClasses=com.abc.xxx.client.TestClient.class)

This parameter accept single or multiple class name. You can also give the base package of the same,

@EnableFeignClients(basePackages = {"my.external.feign.client.package", "my.local.package"})

CodePudding user response:

From the javadoc of @EnableFeignClients:

Scans for interfaces that declare they are feign clients (via FeignClient @FeignClient). Configures component scanning directives for use with org.springframework.context.annotation.Configuration @Configuration classes.

Generally this is placed on a @SpringBootApplication annotated class so that your Feign clients are available in production as well as your @SpringBootTest's.

If you really want to enable your Feign client only in your test, it should look something like this:

@SpringBootTest
class ClientApplicationTests {

    @EnableFeignClients(clients = TestClient.class)
    @Configuration
    protected static class ClientApplicationTestsConfig {
    }   

    @Autowired
    private TestClient client;

    @Test
    void contextLoads() {
        System.out.println(client.test(TestRequest.builder().foo("foo").build()));
    }
}

This way your test will use the nested @Configuration instead of the automatically found @SpringBootConfiguration/@SpringBootApplication.

  • Related