当前位置: 首页 > 知识库问答 >
问题:

如何在Spring Boot中为REST控制器endpoint编写单元测试而不模拟服务类

逑兴安
2023-03-14

我必须在Spring Boot中为Web服务编写单元测试,它应该从Controller执行测试,并流入Service类。我正在为Service类使用@Mock注释,为Controller使用@InjectMock,因此应用程序流永远不会进入Service类内部(它返回一个null)。

如果没有对 Service 类@Mock注释,我会收到空点异常。

我不想模仿服务类,我想用这个相同的测试单元测试服务类。

这是我的Rest控制器。

 @RestController
 public class AddressController {
 @Autowired
 private GetAddressService getAddressService;

@RequestMapping(value=ApplicationConstant.ADDRESS_URI,method=RequestMethod.G    ET,produces = { ApplicationConstant.APP_RESP_TYPE })
public @ResponseBody SampleResponse getAddress(
        @RequestParam(value="id",required=true) String hcId,
        @RequestParam(value="mbrNbrbr",required=true) String mbrNbr,
        ){

    System.out.println("Request ID in Controller :"+Id);
    String responseid = getAddressService.getAddress(Id);

    SampleResponse smapleResp = new SampleResponse();
    System.out.println("Response ID in Controller :"+Id);
    smapleResp.setResponseid(responseid);
    return smapleResp;

这是我的服务类

 @Service
public class GetAddressServiceImpl implements GetAddressService {
@Override
public String getAddress(String id) {

    System.out.println("ID in Service : " + id);
    return id;
}
}

我有一个抽象测试类,它扩展到抽象控制器测试类,最后是我的地址html" target="_blank">控制器测试类,它有@Test方法。

Abstract测试等级:

 @RunWith(SpringJUnit4ClassRunner.class)
 @SpringApplicationConfiguration(classes = Application.class)
 public abstract class AbstractTest {
  }

抽象控制器测试类别:

@WebAppConfiguration 
public abstract class AbstractControllerTest extends AbstractTest {

//mockmvc stimulates Http interactions
protected MockMvc mockMvc; 

@Autowired
protected WebApplicationContext webApplicationContext;


protected void setUp(){
    mockMvc =   MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}


protected void setUp(AddressController addressController){
    mockMvc = MockMvcBuilders.standaloneSetup(addressController).build();
}
}

最后我的地址测试类:

   @TestExecutionListeners
    public class AddressMockControllerTest extends AbstractControllerTest  {

    @Mock
    private GetAddressService getAddressService;

    @InjectMocks
    private AddressController addressController;

    private String MockURI ="/v1/legacy/member/Contact/Address? id=55555&mbrNbr=20&id=ABC&productid=1FGQ&sourceid=STAR&addressuid=adasdsa";

    @Before
    public void setUp(){
        MockitoAnnotations.initMocks(this);
        setUp(addressController);       
        }


    @Test
    public void test(){
        System.out.println("In Unit test");

    }

    @Test
    public void testgetAddress() throws Exception {


     System.out.println("In Unit test");

     MvcResult result =  this.mockMvc.perform(
                   MockMvcRequestBuilders.get(MockURI)
                  .accept(MediaType.APPLICATION_JSON))
                  .andReturn(); 


     String content = result.getResponse().getContentAsString();

        System.out.println("In Unit test and content is " + content);   
    }

引导主类:

 public class Application extends SpringBootServletInitializer{

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

@Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
    return application.sources(ApplicationInitializer.class);
}

应用程序初始值设定项:

    @Configuration

@EnableAutoConfiguration
@ComponentScan(value={"com.ABC"})
@EnableConfigurationProperties
public class ApplicationInitializer {

    @Bean
    @ConditionalOnMissingBean(RequestContextListener.class)
    public RequestContextListener requestContextListener() {
        return new RequestContextListener();
    }

    @Bean
    public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
        ServletRegistrationBean registration = new ServletRegistrationBean(
                dispatcherServlet);
        registration.addUrlMappings("/");
        return registration;
    }

    @Bean
    public ServletRegistrationBean dynamicLogbackLevelServletRegistration() {

        return new ServletRegistrationBean(new DynamicLogbackLevelServlet(),"/loglevel");

    }


    @Order(Ordered.HIGHEST_PRECEDENCE)
    public FilterRegistrationBean contextFilterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        RequestFilter contextFilter = new RequestFilter();
        registrationBean.setFilter(contextFilter);
        registrationBean.setOrder(1);
        return registrationBean;
    }


    @Bean
    public ApplicationContextProvider applicationContextProvider(){
        return new ApplicationContextProvider();
    }

}

共有2个答案

尹欣怿
2023-03-14

顺便说一句,Spring Boot现在内置了对基于@MockedBean注释的嘲笑和间谍豆的支持。也许你想研究它。

慕铭
2023-03-14

不确定这是否有效,但基于另一篇SO帖子:https://stackoverflow.com/a/32294564/1499549

如果你正在使用转轮,看起来你不应该使用standaloneSetup()。

public void setup() {
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

然后删除@InjectMocks批注并将其替换为@Autowired

//@Mock
//private GetAddressService getAddressService;

//@InjectMocks
@Autowired
private AddressController addressController;

private String MockURI ="/v1/legacy/member/Contact/Address?id=55555&mbrNbr=20&id=ABC&productid=1FGQ&sourceid=STAR&addressuid=adasdsa";

@Before
public void setUp(){
    setUp();       
}

@Test
public void test(){
    System.out.println("In Unit test");
}
 类似资料:
  • 我对Spring boot和JUnit是新手。我在Spring Boot中有一个Rest服务,在那里我接收请求,使用请求参数查询数据库,从查询中接收结果并将其作为响应发送。 我的控制器代码如下所示: 我的JdbcTemplate被作为一个单独类中的bean处理,如下所示 我的代码运行良好。 现在我想使用JUnit4为我的控制器编写单元测试。我使用MockMvc发送请求,但我的单元测试从未起飞。它总

  • 问题内容: 我有以下情况: controller.js controllerSpec.js 错误: 我也尝试过类似的方法,但没有成功: 我该如何解决?有什么建议? 问题答案: 有两种方法(或肯定有更多方法)。 想象一下这种服务(无论它是工厂都没关系): 使用此控制器: 一种方法是使用要使用的方法创建对象并对其进行监视: 然后,将其作为dep传递给控制器​​。无需注入服务。那可行。 另一种方法是模拟

  • 如何为RestController,Service和DAO层编写JUnit测试用例? 我试过 如何验证rest控制器和其他层中的CRUD方法?

  • 问题内容: 我有一个ParseService,我想对其进行模拟以测试使用它的所有控制器,我一直在阅读有关茉莉花间谍的信息,但对我来说仍然不清楚。谁能给我一个关于如何模拟定制服务并在Controller测试中使用它的示例吗? 现在,我有一个使用服务插入书的控制器: 服务是这样的: 到目前为止,我的测试如下所示: 现在测试失败: 我做错了什么? 问题答案: 我做错的是没有在beforeEach中将模拟

  • 问题内容: 我正在使用RestTemplate 方法发布到端点。在我的测试文件中,我正在测试POST方法。但是用我目前的测试,我得到了POST请求。在测试文件中发出POST请求时,我需要模拟API的帮助 这是我的主文件 这是我的测试文件 问题答案: 您正在测试DataTestRepo类内部的逻辑,因此您不应模拟它。RestTemplate是DataTestRepo内部的一个依赖项,因此这正是您需要

  • 我有一个Spring 3.2 MVC应用程序,正在使用Spring MVC测试框架测试控制器动作的GET和POST请求。我使用Mockito来模拟服务,但我发现模拟被忽略了,我的实际服务层被使用了(因此,数据库被击中)。 控制器测试中的代码: 你会注意到我有两个上下文配置文件;这是一种黑客行为,因为如果我无法阻止控制器测试命中实际的服务层,那么该服务层的存储库也可能指向测试数据库。我再也不能忍受这