【问题标题】:Inject mock bean into AnnotatinConfigApplicationContext failed将模拟 bean 注入 AnnotatinConfigApplicationContext 失败
【发布时间】:2020-08-11 19:23:26
【问题描述】:

我的 Springboot 应用程序没有主类,因为它有一个 AWS Lambda 处理程序。

这就是我要测试的班级的样子。

@Slf4j
@SpringBootApplication
@Configuration
@ComponentScan(basePackages = "${spring.basepackages}")
@EnableAutoConfiguration
public class AWSLambdaHandler implements RequestHandler<LambdaRequest, LambdaResponse> {

    @Override
    public LambdaResponse handleRequest(LambdaRequest input, Context context) {

        GenericResponse serviceResponse = new GenericResponse();
        LambdaResponse lambdaResponse = new LambdaResponse();
        ObjectMapper mapper = new ObjectMapper();

        try {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
            ServiceClass service = applicationContext.getBean(ServiceClassImpl.class);
            serviceResponse = service.process(input);
            lambdaResponse.setBody(mapper.writeValueAsString(serviceResponse));
        } catch (JsonProcessingException e) {
            log.error("Exception occured in Handler-" + e.getMessage());
            //Setting error codes and messages for the response
        } 
        return lambdaResponse;
    }
}

我的 Config 类是这样的

@Configuration
@ComponentScan(basePackages = "${spring.basepackages}")
@PropertySource("classpath:application.properties")
@EnableAutoConfiguration
public class Config{
    //No additional code here.
}

我的测试类将如下所示

@SpringBootTest(classes = Config.class)
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
public class LambdaHandlerTest{

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private AWSLambdaHandler handler;

    @MockBean
    private GenericResponse genericResponse;

    @MockBean
    ServiceClass mockService;

    @MockBean
    ServiceImpl mockServiceImpl;

    @MockBean
    Context context;


    @Test
    public void testHandleRequest_success() {
        when(mockService.getOrdersList(any())).thenReturn(genericResponse);
        LambdaResponse response = handler.handleRequest(createRequest(), context);
    }

    private LambdaRequest createRequest() {
        LambdaRequest request = new LambdaRequest();
        request.setCustomerNo(TestUtils.CUSTOMER_NO);
        request.setOpco(TestUtils.OPCO);
        request.setOrderNo(TestUtils.ORDER_NO);
        request.setUomOrderNo(TestUtils.UOM_ORDER_NO);
        return request;
    }
}

在上面的类中,我正在为服务类创建 MockBean,并希望在我运行测试用例时它会被注入,但实际上正在为服务类创建一个真实的对象,因此我的 Mock Stub 无法正常工作,最终我最终遇到了一个例外。有人可以建议可以做什么。

【问题讨论】:

  • 当然它不会注入,因为您正在自己创建一个新的应用程序上下文。您为什么要这样做?由于组件扫描,该服务应该由 @SpringBootApplication 注释类创建,您基本上是在重新启动整个应用程序......只需按照您应该使用的方式使用依赖注入,然后它就会工作。
  • 你的意思是,如果我尝试使用 Autowired 注释来获取处理程序类中的 bean 而不是使用 ApplicationContext,那么我可以将我的 mockBean 放在那里吗?

标签: java spring spring-boot junit spring-test


【解决方案1】:

您正在努力解决 Spring Boot / Spring Cloud Function 问题。

首先你的函数应该看起来像这样。


@Slf4j
@SpringBootApplication
public class AWSLambdaHandler implements RequestHandler<LambdaRequest, LambdaResponse> {

    private final ServiceClass service;

    public AWSLambdaHandler(ServiceClas service) {
      this.service=service;
    }

    @Override
    public LambdaResponse handleRequest(LambdaRequest input, Context context) {

        GenericResponse serviceResponse = new GenericResponse();
        LambdaResponse lambdaResponse = new LambdaResponse();
        ObjectMapper mapper = new ObjectMapper();

        try {
            serviceResponse = service.process(input);
            lambdaResponse.setBody(mapper.writeValueAsString(serviceResponse));
        } catch (JsonProcessingException e) {
            log.error("Exception occured in Handler-" + e.getMessage());
            //Setting error codes and messages for the response
        } 
        return lambdaResponse;
    }
}

接下来放弃您的 Config 类,因为它不会添加任何内容(或至少删除除 @Configuration 之外的所有注释。

然后将您的测试重写为尝试为响应创建一个模拟等。没有意义,您也不需要 MockMVC。

@SpringBootTest
@RunWith(SpringRunner.class)
public class LambdaHandlerTest{

    @Autowired
    private AWSLambdaHandler handler;

    @MockBean
    private ServiceClass mockService;

    @MockBean
    private Context context;

    @Test
    public void testHandleRequest_success() {
        when(mockService.getOrdersList(any())).thenReturn(genericResponse);
        LambdaResponse response = handler.handleRequest(createRequest(), context);
    }

    private LambdaRequest createRequest() {
        LambdaRequest request = new LambdaRequest();
        request.setCustomerNo(TestUtils.CUSTOMER_NO);
        request.setOpco(TestUtils.OPCO);
        request.setOrderNo(TestUtils.ORDER_NO);
        request.setUomOrderNo(TestUtils.UOM_ORDER_NO);
        return request;
    }
}

这应该像你想要的那样工作。但是,您现在甚至可以编写一个简单的单元测试(由于 AWSLambdaHandler 中使用了构造函数注入,并且您根本不需要 Spring。

@RunWith(MockitoJUnitRunner.class)
public class LambdaHandlerTest{

    @InjectMocks
    private AWSLambdaHandler handler;

    @Mock
    private ServiceClass mockService;

    @Mock
    private Context context;

    @Test
    public void testHandleRequest_success() {
        when(mockService.getOrdersList(any())).thenReturn(genericResponse);
        LambdaResponse response = handler.handleRequest(createRequest(), context);
    }

    private LambdaRequest createRequest() {
        LambdaRequest request = new LambdaRequest();
        request.setCustomerNo(TestUtils.CUSTOMER_NO);
        request.setOpco(TestUtils.OPCO);
        request.setOrderNo(TestUtils.ORDER_NO);
        request.setUomOrderNo(TestUtils.UOM_ORDER_NO);
        return request;
    }
}

最后一个会运行得更快,因为它只是一个简单的单元测试,而@SpringBootTest 更多的是一个集成测试。

【讨论】:

    猜你喜欢
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 2017-08-24
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多