LoginSignup
2
2

More than 5 years have passed since last update.

TestRestTemplate の Autowired にて NoSuchBeanDefinitionException が発生する

Posted at

現象

下記のようなクラス構成のテストを書いたところ、TestRestTemplate が Autowired できない現象が発生しました。

application.properties
# AP は 9000 番ポートで動作させる
server.port=9000
AbstractBaseTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = HogeApplication.class)
public abstract class AbstractBaseTest {

    protected MockMvc mvc;

    @Autowired
    protected WebApplicationContext context;

    @Autowired
    protected TestRestTemplate restTemplate;
SubTestClass.java
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = HogeApplication.class)
public class SubTestClass extends AbstractBaseTest {
     something tests...
    public void URLをテストする() throws Exception {
        HashMap param = new HashMap<String, String>();
        param.put("userAccount", ユーザーアカウント);
        param.put("password", パスワード);
        ResponseEntity<String> resultResponse = restTemplate.postForEntity("http://localhost:9000/authentication", param, String.class);

    }
}

ログの内容


Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.test.web.client.TestRestTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
    ... 28 more

回避策

サブクラスにて webEnvironment に RANDOMPORT、親クラスなどで@LocalServerPortを指定するです。
Spring Boot のページ のサンプルでは、LocalServerPort の指定があり、テストをするにあたり事実上不可欠のアノテーションですが、TestRestTemplate の生成については不要のようです。ドキュメントにも必須かどうかについての言及がありません。

Note the use of webEnvironment=RANDOM_PORT to start the server with a random port (useful to avoid conflicts in test environments), and the injection of the port with @LocalServerPort. Also note that Spring Boot has provided a TestRestTemplate for you automatically, and all you have to do is @Autowired it.

2017/08 現在の動作としては、

  • 使用するクラスにて TestRestTemplate を Autowired しないと Bean を生成できない。
  • LocalServerPort のポートへ TestRestTemplate から要求しないと、Connection Refused になる。

のようです。
よって正しい構成は下記のようになるようです。

AbstractTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //あってもなくても良い
@ContextConfiguration(classes = HogeApplication.class)
public abstract class AbstractBaseTest {

    protected MockMvc mvc;

    @Autowired
    protected WebApplicationContext context;

    @Autowired
    protected TestRestTemplate restTemplate;

    @LocalServerPort
    protected int serverPort;
}
SubTestClass.java
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = HogeApplication.class)
public class SubTestClass extends AbstractBaseTest {
     something tests...
    public void URLをテストする() throws Exception {
        HashMap param = new HashMap<String, String>();
        param.put("userAccount", ユーザーアカウント);
        param.put("password", パスワード);
        ResponseEntity<String> resultResponse = restTemplate.postForEntity("http://localhost:" + serverPort + "/authentication", param, String.class);

    }
}

@LocalServerPort が存在しない場合、該当のアプリケーションにモックの HTTP 経由でアクセスできないようです。
ConnectionRefused のエラーが発生します。


org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:9000/hoge": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)

    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:666)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:407)
    at org.springframework.boot.test.web.client.TestRestTemplate.postForEntity(TestRestTemplate.java:471)
    at com.asaas.billing.controller.SigninControllerTest.URLをテストする(SigninControllerTest.java:72)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)

Caused by: java.net.ConnectException: Connection refused (Connection refused)
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2