MessageSource未在ControllerAdvice中注入

时间:2018-02-27 05:59:47

标签: java spring spring-mvc

我有一个简单的Spring MVC应用程序,其中包含NullPointerException的控制器建议类。此控制器建议使用注入@Autowired的消息源。

我通过使用@MockBean模拟MessageSource字段来编写对此控制器建议的测试,但看起来Spring引入了默认的DelegatingMessageSource

相比之下,SomeService mock被正确注入。

有人知道为什么MessageSource无法注入此处,注入它的正确方法是什么?

的build.gradle:

group 'exceptions'
version '1.0-SNAPSHOT'

buildscript {
    repositories {
        jcenter()
        maven { url 'http://repo.spring.io/snapshot' }
        maven { url 'http://repo.spring.io/milestone' }
    }
    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT'
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'application'
apply plugin: 'idea'

sourceCompatibility = 1.8

repositories {
    jcenter()
    maven { url "http://repo.spring.io/snapshot" }
    maven { url "http://repo.spring.io/milestone" }
}

dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.10.RELEASE'
    compile("org.springframework:spring-test:5.0.2.BUILD-SNAPSHOT")
    testCompile("org.springframework.boot:spring-boot-starter-test")
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

MyError.java:

package mainpackage.application;

import com.fasterxml.jackson.annotation.JsonProperty;

public class MyError {
    @JsonProperty("message")
    public String message;

    public MyError(String message) {
        this.message = message;
    }
}

MyExceptionHandler.java:

package mainpackage.application;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.Locale;

@ControllerAdvice
public class MyExceptionHandler {
    private final MessageSource messageSource;

    private final SomeService someService;

    @Autowired
    public MyExceptionHandler(MessageSource messageSource, SomeService someService) {
        this.messageSource = messageSource;
        this.someService = someService;
    }

    private static final String MY_KEY = "key";

    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<MyError> handleNullPointerException(NullPointerException e) {
        String details = someService.getDetails();
        return new ResponseEntity<>(new MyError(messageSource.getMessage(MY_KEY, null, Locale.ENGLISH), details), HttpStatus.BAD_REQUEST);
    }
}

MyExceptionHandlerTest.java:

package mainpackage.application;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Locale;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(SpringRunner.class)
@WebMvcTest(MyExceptionHandler.class)
public class MyExceptionHandlerTest {
    @Autowired
    private MyExceptionHandler myExceptionHandler;

    @MockBean
    private MessageSource messageSource;

    @MockBean
    private SomeService someService;

    @Test
    public void handleNullPointerException() {
        String key = "key";
        String message = "message";
        String anotherMessage = "anotherMessage";
        when(someService.getDetails()).thenReturn(anotherMessage);
        when(messageSource.getMessage(key, null, Locale.ENGLISH)).thenReturn(message);

        ResponseEntity<MyError> resp = myExceptionHandler.handleNullPointerException(new NullPointerException("something"));

        verify(someService).getDetails();
        verify(messageSource).getMessage(key, null, Locale.ENGLISH);
        assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
        assertThat(resp.getBody().message).isEqualTo(message);
    }
}

输出: org.springframework.context.NoSuchMessageException:在代码'key'下找不到locale'en'的消息。

at org.springframework.context.support.DelegatingMessageSource.getMessage(DelegatingMessageSource.java:76)
at mainpackage.application.MyExceptionHandler.handleNullPointerException(MyExceptionHandler.java:21)
at mainpackage.application.MyExceptionHandlerTest.handleNullPointerException(MyExceptionHandlerTest.java:34)
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.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

修改

我将字段依赖项更改为构造函数依赖项。更清楚的是注入了默认的MessageSource

0 个答案:

没有答案