Strategy for unit testing a Spring Cloud Service
Asked Answered
D

3

4

Given the following Spring Cloud setup: A data-service with access to a database, an eureka-service to handle service registry and discovery and a third service business-service which will be one of various services which encapsulate business cases.

Unit testing the data-service is no problem, I just turn off eureka via

eureka.client.enabled=false

and use an in-memory database for my tests.

To access the data-service from business-service, I'm using an @FeignClient("data-service") annotated interface named DataClient which is @Autowired where needed. The service is discovered by Eureka, if both are running. This works fine for a production-like setup with all services running.

But now I want to unit test some features of my business-service. It wouldn't be a problem to start a test service with

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@IntegrationTest("server.port:0")
@SpringApplicationConfiguration(classes = Application.class)

like I'm doing in data-service. The problem is the Eureka-dependent discovery of my FeignClient... So my testclass crashes, because the autowiring my DataClient-instance doesn't work.

Am I abled to tell Spring to use a faked instance of DataClient just for my tests? Or is the only way to get my tests running an accessible, running instance of data-service and my Eureka server?

Daynadays answered 16/12, 2015 at 8:52 Comment(0)
F
15

1, first create config bean, let the discovery client and feignclient only work when "eureka.enabled" is true

@Configuration
@EnableDiscoveryClient
@EnableFeignClients
@ConditionalOnProperty(name = "eureka.enabled")
public class EurekaConfig {
}

2, disable the eureka config for test profile, so in application-test.yml

eureka:
     enabled: false

3, my project is build by maven, so i create a implement for my feign client interface, for example:

@Service
public class DataServiceImpl implements DataService {}

after this, when you run test in unit test with

@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@IntegrationTest({"server.port=0", "management.port=0",    "spring.profiles.active=test"})
public abstract class AbstractIntegrationTests {}

the fake service will inject in to spring context.

Or for normal unit test case, you can just need mockito mock the service class and use set method or construct method inject the mock object in your class

Frolicsome answered 21/3, 2016 at 7:53 Comment(0)
D
2

My first attempt crashed because of another bug... So it works fine with a @Configuration annotated class Conf which creates an fake implementation of DataClient like this:

@Bean
@Primary
public DataClient getDataClient() {
    ...
}

Added to my test via

@SpringApplicationConfiguration(classes = {Application.class, Conf.class})

the tested service instance uses the fake implementation correctly.

Daynadays answered 16/12, 2015 at 10:1 Comment(0)
C
2

Adding on Yunlong's answer on annotating on a separate configuration class.

If the configuration class is placed under a different package than the root package, you will need to specify the "basePackages" for the @EnableFeignClients to scan for the annotated @FeignClient component.

com.feign.client.FeignClient.class

@FeignClient(value = "${xxxx}")
public interface FeignClient {
}

com.feign.config.EurekaConfig.class

@Configuration
@EnableFeignClients(basePackages = {"com.feign.client"})
@EnableEurekaClient
@ConditionalOnProperty(name = "eureka.enabled")
public class EurekaClientConfig {
}

Ps. I couldnt comment to the original reply so I created a new answer.

Compassionate answered 4/4, 2018 at 10:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.