2

I have a service which uses an autowired instance of RestTemplate like below

@Service
class SomeAPIService {
    private RestTemplate restTemplate;

    SomeAPIService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        this.restTemplate.setRequestFactory(HttpUtils.getRequestFactory());
    }
}

Everything runs fine in non-test environment. But when I try to run following unit test in test profile, it starts complaining about unable to autowire rest template.

@RunWith( SpringJUnit4ClassRunner.class )
@SpringBootTest(classes = MyApplication.class, webEnvironment = RANDOM_PORT, properties = "management.port:0")
@ActiveProfiles(profiles = "test")
@EmbeddedPostgresInstance(flywaySchema = "db/migration")
public abstract class BaseTest {
}

@SpringBootTest(classes = SomeAPIService.class)
public class SomeAPIServiceTest extends BaseTest {
    @Autowired
    SomeAPIService someAPIService;

    @Test
    public void querySomeAPI() throws Exception {
        String expected = someAPIService.someMethod("someStringParam");
    }
}

Following is the detailed exception -

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'someAPIService': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.client.RestTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Any clues?

comiventor
  • 3,922
  • 5
  • 50
  • 77

3 Answers3

8

Following helped me get the correct dependencies autowired. The solution is to also include RestTemplate.class in list of classes given to SpringBootTest.

@SpringBootTest(classes = {RestTemplate.class, SomeAPIService.class})
class SomeAPIService {
    @Autowired
    SomeAPIService someAPIService;

    @Test
    public void querySomeAPI() throws Exception {
        String expected = someAPIService.someMethod("someStringParam");
    }
}

@Emre answer was helpful in guiding me towards the final solution.

comiventor
  • 3,922
  • 5
  • 50
  • 77
0

You are trying to autowire SomeAPIService without satisfying its dependencies. You should inject Rest Template to SomeAPIService. But you are getting NoSuchBeanDefinitionException for Rest Template.

Take a look how to inject it :

How to autowire RestTemplate using annotations

Emre Savcı
  • 3,034
  • 2
  • 16
  • 25
  • I do have a HttpConfiguration class annotated with Configuration with a bean definition for RestTemplate – comiventor Apr 08 '18 at 08:36
  • Also as i mentioned, I find it hard to understand why everything runs fine in non-test environment while breaks in test enviroment. I have been Autowiring like this without injecting dependencies for other unit tests and never faced a problem. – comiventor Apr 08 '18 at 08:40
  • 1
    Try changing @SpringBootTest(classes = SomeAPIService.class) to @SpringBootTest(classes = MyApplication.class) According to spring boot docs : "classes The annotated classes to use for loading an ApplicationContext." – Emre Savcı Apr 08 '18 at 09:12
  • Thanks Emre. That was helpful and did help me move past the issue but now the active profile has come to haunt. My application requires an additional active profile for certain dependencies to build. I am providing the active profile to maven test like this `mvn test -P myActiveProfile` but its giving me the same error it gives when I drop specifying myActiveProfile in the usual run. wiring issue but of a different kind – comiventor Apr 09 '18 at 05:08
  • Using `@SpringBootTest(classes = MyApplication.class)` was actually running entire application but not the unit test case – comiventor Apr 09 '18 at 07:40
0

Alternative answer would be - to use TestRestTemplate

From official docs >>>

TestRestTemplate can be instantiated directly in your integration tests, as shown in the following example:

public class MyTest {

    private TestRestTemplate template = new TestRestTemplate();

    @Test
    public void testRequest() throws Exception {
        HttpHeaders headers = this.template.getForEntity(
                "https://myhost.example.com/example", String.class).getHeaders();
        assertThat(headers.getLocation()).hasHost("other.example.com");
    }

}

Alternatively, if you use the @SpringBootTest annotation with WebEnvironment.RANDOM_PORT or WebEnvironment.DEFINED_PORT, you can inject a fully configured TestRestTemplate and start using it. If necessary, additional customizations can be applied through the RestTemplateBuilder bean.

Saikat
  • 14,222
  • 20
  • 104
  • 125