我可以在控制器中使用@Autowired

@RestController
public class Index {

    @Autowired
    HttpServletResponse response;

    @GetMapping("/")
    void index() throws IOException {
        response.sendRedirect("http://example.com");
    }
}


有用;

但是当我尝试使用@MockBean来测试此类时

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

    @Autowired
    Index index;

    @MockBean
    HttpServletResponse response;

    @Test
    public void testIndex() throws IOException {
        index.index();
    }
}


它抛出异常并说

Description:

Field response in com.example.demo.Index required a single bean, but 2 were found:
    - com.sun.proxy.$Proxy69@425d5d46: a programmatically registered singleton  - javax.servlet.http.HttpServletResponse#0: defined in null


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed


如何解决?

最佳答案

尽管可能存在恕我直言,但这是注入HttpServletResponseHttpServletRequest这样的坏习惯。这将导致奇怪的问题,并且看起来很普通又是错误的。而是使用类型为HttpServletResponse的方法参数,并使用Spring MockHttpServletResponse进行测试。

然后,编写单元测试就像创建类的新实例并调用方法一样简单。

public class IndexTest {

    private Index index = new Index();

    @Test
    public void testIndex() throws IOException {
        MockHttpServletResponse response = new MockHttpServletResponse();
        index.index(response);
        // Some assertions on the response.
    }
}


如果要作为较大的集成测试的一部分对其进行测试,则可以或多或少地执行相同的操作,但是要使用@WebMvcTest批注。

@RunWith(SpringRunner.class)
@WebMvcTest(Index.class)
public class IndexTest {

    @Autowired
    private Index index;

    @Test
    public void testIndex() throws IOException {
        MockHttpServletResponse response = new MockHttpServletResponse();
        index.index(response);
        // Some assertions on the response.
    }
}


或使用MockMvc通过模拟请求对其进行测试

@RunWith(SpringRunner.class)
@WebMvcTest(Index.class)
public class IndexTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testIndex() throws IOException {
        mockMvc.perform(get("/")).
            andExpect(status().isMovedTemporarily());
        MockHttpServletResponse response = new MockHttpServletResponse();
        index.index(response);
        // Some assertions on the response.
    }
}


上面的测试也可以使用@SpringBootTest编写,不同之处在于@WebMvcTest仅测试和引导Web切片(即与Web相关的东西),而@SpringBootTest实际上将启动整个应用程序。

07-25 22:32