首页 > 解决方案 > 通过 Spring Boot 测试运行时控制器中未发生 Bean 注入

问题描述

我创建了一个带有基于 Rest 的 API 的 Spring Boot Web 应用程序。我的控制器有一个服务,该服务在通过主应用程序运行时应用程序正常启动时自动连接和注入。但是,如果我为该控制器运行我的集成测试。我得到以下异常。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'com.xyz.test.service.LolService' available: expected
 at least 1 bean which qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

这是我的控制器类。

package com.xyz.test.controller;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.xyz.test.model.Lol;
import com.xyz.test.service.LolProcessingService;
import com.xyz.test.service.LolService;


@RestController
@RequestMapping("/api")
@Slf4j
public class CalorieController {

    @Autowired
    private LoleService lolService;

    @Autowired
    private LolProcessingService lolProcessingService;


    @PostMapping("/lol")
    @PreAuthorize("hasRole('USER')")
    public FoodIntake createLol( @Valid @RequestBody Lol lol) throws Exception {
        return lolProcessingService.processNewLol(lol);
    }
}

这是我的服务班

package com.xyz.test.service.impl;
   @Service
    public class LolServiceImpl implements LolService{

        @Autowired
        private LolRepository lolRepository;

    //some methods
    }

这是我的集成测试课。

package com.xyz.test.rest;

import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import com.xyz.test.controller.CalorieController;


@RunWith(SpringRunner.class)
@SpringBootTest(classes = CalorieController.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration
@ComponentScan
public class LolControllerTest {


    @LocalServerPort
    private int port;

    TestRestTemplate restTemplate = new TestRestTemplate();

    HttpHeaders headers = new HttpHeaders();


    @Test
    public void testabc() throws JSONException {
        headers.add("Authorization","Basic cGFtcGxlOnBhbXBsZTEyMw==");
        HttpEntity<String> entity = new HttpEntity<String>(null, headers);

        ResponseEntity<String> response = restTemplate.exchange(
                createURLWithPort("/api/lol/pample"),
                HttpMethod.GET, entity, String.class);

        String expected = "[]";

        JSONAssert.assertEquals(expected, response.getBody(), false);
    }

    private String createURLWithPort(String uri) {
        return "http://localhost:" + port + uri;
    }


}

最后这是主要应用程序

package com.xyz.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableJpaAuditing
public class SpringbootSecurityMysqlApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootSecurityMysqlApplication.class, args);
    }

    //bean for making http external calls
    @Bean 
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

我不明白为什么测试类在正确注入 bean 时无法正常启动。我需要帮助。提前致谢。

标签: javaspringspring-boottestingspring-boot-test

解决方案


不要classes为 @SpringBootTest 注解指定参数。

按照以下方式使用它

 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

将导致 Spring Boot 在当前包中查找配置类,然后是父包等。最终找到您的SpringbootSecurityMysqlApplication. 这将测试包括所有层在内的完整应用程序。

如果您想使用模拟服务单独测试控制器

@WebMvcTest(CalorieController.class)

并为您的测试中的服务提供模拟 bean

@MockBean
private LoleService lolService;

推荐阅读