如何使用 power mock 对 Spring Boot Rest 控制器和异常处理程序进行单元测试
Posted
技术标签:
【中文标题】如何使用 power mock 对 Spring Boot Rest 控制器和异常处理程序进行单元测试【英文标题】:How to unit testing spring boot rest controller and exception handler using power mock 【发布时间】:2017-10-10 05:09:30 【问题描述】:我有一个简单的 Spring 启动应用程序,它包含员工控制器,如果过去的年份大于 2014 年并且如果它不小于 2014 年,则返回员工姓名,那么我将抛出一个自定义异常并在异常处理程序中处理它. 我想使用 powermock 对异常流进行单元测试,但我不知道该怎么做。我已经浏览了一些链接,但无法理解。 目前我收到 java.lang.IllegalArgumentException: WebApplicationContext is required。
EmployeeController.java
@RestController
public class EmployeeController
@GetMapping(value = "/employee/joiningYear",produces = MediaType.APPLICATION_JSON_VALUE)
public List<String> getEmployeeById(@PathVariable int joiningYear) throws YearViolationException
if(joiningYear < 2014)
throw new YearViolationException("year should not be less than 2014");
else
// send all employee's names joined in that year
return null;
异常处理程序
@RestControllerAdvice
public class GlobalControllerExceptionHandler
@ExceptionHandler(value = YearViolationException.class )
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse yearConstraintViolationExceptio(YearViolationException ex)
return new ApiErrorResponse(400, 5001, ex.getMessage());
自定义异常
public class YearViolationException extends Exception
/**
*
*/
private static final long serialVersionUID = 1L;
public YearViolationException(String message)
super(message);
Junit 到单元测试异常处理程序
@RunWith(PowerMockRunner.class)
@WebAppConfiguration
@SpringBootTest
public class ExceptionControllerTest
@Autowired
private WebApplicationContext applicationContext;
private MockMvc mockMVC;
@Before
public void setUp()
mockMVC = MockMvcBuilders.webAppContextSetup(applicationContext).build();
@Test
public void testhandleBanNotNumericException() throws Exception
mockMVC.perform(get("/employee/2010").accept(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isBadRequest())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON));
【问题讨论】:
请包含完整的堆栈跟踪;指出错误发生在哪一行。除此之外:不清楚你在这里做什么。你看,单元测试的重点是调用某个“被测类”中的方法;然后断言输出;或验证在该操作期间使用的模拟对象。您的代码仅创建了一个 Mock 对象;并指定对此的调用。我没有看到你在哪里调用你的生产代码?! (也许是因为我不熟悉这些框架,但似乎仍然缺少一些东西)。除此之外:这里不需要 PowerMock。 只有在你想模拟 static 方法或调用new
时才需要 PowerMock。如果您没有这种情况(并且您应该避免遇到这种情况!)...那么您不需要使用 PowerMock。您可以改用简单的 Mockito。
@GhostCat 我创建了虚拟代码,因为我无法发布实际的项目代码。正如你指出的那样,没有逻辑是正确的。在这里,我创建了项目代码的副本,我必须使用 powermock 编写单元测试。
【参考方案1】:
正如其他人所说,您根本不需要 mockMVC。如果你想测试 REST 端点,你需要的是 TestRestTemplate。 Runwith SpringRunner.class 和 WebEnvironment 设置一样重要。
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class RestServiceApplicationTests
private String baseUrl = "http://localhost:8090";
private String endpointToThrowException = "/employee/2010";
@Autowired
private TestRestTemplate testRestTemplate;
@Test(expected = YearViolationException.class)
public void testhandleBanNotNumericException()
testRestTemplate.getForObject(baseUrl + endpointToThrowException, String.class);
【讨论】:
这段代码似乎告诉 Spring 使用一个随机端口:webEnvironment=WebEnvironment.RANDOM_PORT,但对带有端口 8090 的硬编码 url 运行 @Test。这如何工作?我认为我们应该使用 RANDOM_PORT:AT LocalServerPort private int port; 这是单元测试还是集成测试(@SpringBootTest)?在我看来,这不是单元测试 你是对的,因为我们也在配置环境和上下文,这更像是一个集成测试。这个问题本身存在设计缺陷,因为控制器测试表明集成测试而不是单元测试。【参考方案2】:从您的设置看起来,您根本不需要使用 Mocks。好像您想加载完整的应用程序上下文并使用 mockMVC 向您的休息控制器发送请求。这实际上是和集成测试!
现在,不幸的是,我们在这里使用 Spring Boot 1.3,所以我不确定 @RunWith(PowerMockRunner.class)
和 @SpringBootTest
的组合是否真的加载了应用程序上下文。检查你的日志,看看是否有,如果没有,试试这个:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
另一方面,如果您想进行简单的单元测试,则无需加载应用程序上下文。相反,您可以将常规 Mockito 与 @Mock
和 @InjectMocks
与 @RunWith(MockitoJUnitRunner.class)
结合使用,并像调用任何其他被测方法一样直接调用您要测试的方法。
希望对您有所帮助。
【讨论】:
嗨,我想为异常处理程序编写单元测试,即当从其余控制器抛出异常时,异常处理程序会正确处理它。 啊,我不仔细阅读真是太糟糕了。您能否确认您的应用程序上下文已成功加载? 如果我使用 SpringBootTest 、 RunWith(SpringRunner.class) 和 WebAppConfiguration 然后加载 WebApplicationContext 但是当我使用 RunWith(PowerMockRunner.class) 、 WebAppConfiguration 和 SpringBootTest 我得到 java.lang.IllegalArgumentException: WebApplicationContext在我进行自动装配时是必需的 由于你只能使用一个 RunWith,你必须使用 SpringRunner。你需要 PowerMockRunner 做什么?从 Mockito 我知道你可以实现与 MockitoJUnitRunner 在 @Before (MockitoAnnotations.initMocks(this)
.以上是关于如何使用 power mock 对 Spring Boot Rest 控制器和异常处理程序进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章