java - 尝试使用 powermockito 模拟包私有方法时出现空指针异常
问题描述
我正在使用 mockito 和 powermockito 为以下控制器类编写测试用例。
@Controller
@RequestMapping("/course")
public class LoginController implements MessageConstants {
protected static Logger logger = org.apache.log4j.Logger.getLogger("LoginController");
@Autowired
public LoginServiceDao LoginServiceDao;
@RequestMapping(value = "/access", method = RequestMethod.POST)
public ResponseEntity<String> validateRequest(@RequestBody String request, @RequestHeader(HttpHeaders.AUTHORIZATION) String jwt) {
try {
String key = LoginServiceDao.getKey();
Properties prop = new Properties();
InputStream input = new FileInputStream("/data/properties/conf.properties");
prop.load(input);
String claims = parseJwt(jwt, key);
String message = "";
String modifiedJson = "";
String response = "";
if (claims.equals("Unsupported JWT") || claims.equals("Malformed JWT") || claims.equals("Signature Mismatch")
|| claims.equals("Unable to Parse JWT") || claims.equals("Invalid Claim Arguments")
|| claims.equals("Invalid JWT")) {
message = getPropertiesMessage(MessageConstants.ERROR_JACPLUS_JWT_INVALID);
response = prepareResponse(response, message);
return new ResponseEntity<String>(response, HttpStatus.UNAUTHORIZED);
}
if (claims.equals("Expired JWT")) {
message = getPropertiesMessage(MessageConstants.ERROR_JACPLUS_JWT_EXPIRED);
response = prepareResponse(response, message);
return new ResponseEntity<String>(response, HttpStatus.REQUEST_TIMEOUT);
}
}
private String parseJwt(String jwt, String key) {
logger.debug("Inside parseJwt method");
Jws<Claims> jwsClaims = null;
try {
InputStream input = new FileInputStream("/data/properties/conf.properties");
Properties prop = new Properties();
prop.load(input);
int skewTime = Integer.valueOf(prop.getProperty("skewTime")).intValue();
jwsClaims = Jwts.parser().setSigningKey(key.getBytes("UTF-8")).setAllowedClockSkewSeconds(skewTime).parseClaimsJws(jwt);
} catch (Exception exp) {
if (exp instanceof UnsupportedJwtException) {
logger.error("Inside parseJwt method - Unsupported JWT", exp);
return "Unsupported JWT";
} else if (exp instanceof MalformedJwtException) {
logger.error("Inside parseJwt method - Malformed JWT", exp);
return "Malformed JWT";
} else if (exp instanceof SignatureException) {
logger.error("Inside parseJwt method - Signature Mismatch", exp);
return "Signature Mismatch";
} else if (exp instanceof InvocationTargetException) {
logger.error("Inside parseJwt method - Unable to Parse JWT", exp);
return "Unable to Parse JWT";
} else if (exp instanceof ExpiredJwtException) {
logger.error("Inside parseJwt method - Expired JWT", exp);
return "Expired JWT";
} else if (exp instanceof IllegalArgumentException) {
logger.error("Inside parseJwt method - Invalid Claim Arguments", exp);
return "Invalid Claim Arguments";
} else {
logger.error("Inside parseJwt method - Invalid JWT", exp);
return "Invalid JWT";
}
}
return jwsClaims.toString();
}
}
Test class for LoginController controller class.
@RunWith(PowerMockRunner.class)
@PrepareForTest({LoginController.class,FileInputStream.class,Jwts.class})
public class LoginControllerTest {
@InjectMocks
public LoginServiceDaoImpl loginServiceDaoImpl;
@Mock
public LoginServiceDao loginServiceDao;
private MockMvc mockMvc;
@InjectMocks
private LoginController loginController;
@Spy
private Properties prop = new Properties();
@Mock
private FileInputStream stream;
private LoginController classUnderTest;
String jsonRequestBody;
String key = "test";
String jwt = "testJwt";
@Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(loginController).build();
prop.setProperty("skewTime", "1000");
classUnderTest = PowerMockito.spy(new LoginController());
jsonRequestBody = "{....}";
MockitoAnnotations.initMocks(this);
}
@Test
public void testValidateCampionRequest() throws Exception {
PowerMockito.whenNew(FileInputStream.class).withArguments(Mockito.anyString()).thenReturn(stream);
PowerMockito.whenNew(Properties.class).withNoArguments().thenReturn(prop);
Jwts jwts = mock(Jwts.class);
PowerMockito.mockStatic(Jwts.class);
//NullPointer Exception here
Mockito.when(jwts.parser().setSigningKey(key.getBytes("UTF-8")).setAllowedClockSkewSeconds(anyLong()).parseClaimsJws(anyString())).thenThrow(new ExpiredJwtException(null,null,null));
//PowerMockito.doNothing().when(classUnderTest, "parseJwt", jwt, key);
RequestBuilder request = MockMvcRequestBuilders
.post("/course/access")
.header("Authorization","Bearer " + jwt)
.content(jsonRequestBody)
.accept(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(request)
.andExpect(status().isRequestTimeout())
.andReturn();
}
}
但我得到了nullpointerexception
上述测试用例。我在发生空异常的测试类中添加了一条注释。
parseJwt
方法是一个封装private
方法。
我还尝试如下模拟 parseJwt 方法
PowerMockito.doNothing().when(classUnderTest, "parseJwt", anyString(), anyString());
然后该parseJwt
方法返回IllegalArgumentException
异常。
我想从方法返回等于“过期 JWT”的声明 parseJwt(jwt, key)
。
解决方案
我认为该错误与可见性 public/package/private 无关
Jwts jwts = mock(Jwts.class);
Mockito.when(jwts.parser().someMethod().someOtherMethod()...
由于 jws 是一个模拟,所有模拟的方法都返回特定类型的默认值(null、0 或 false)
所以 jwts.parser() 如果你不添加类似的代码,将返回 null
Mockito.when(jwts.parser()).thenReturn(new MyParser());
或者你可以使用
Mockito.when(jwts.parser().thenThrow(new ExpiredJwtException(null,null,null));
推荐阅读
- c - 如何使用C程序查找可移动设备的序列号
- python - 如何从键中获取字典
- r - 使用 ggstatsplot 在离散变量和数值变量之间转换时出错
- angular - 在angular6中自动完成
- python - Swagger Python Flask 服务器在 HTTPS 上运行缓慢
- html - 我在 html 中的 iframe 没有显示内容。你能告诉我我的代码有什么问题吗?
- python - 分配容器中的物品 - 3D 装箱问题 | Python
- c# - 如何有效地检索具有与属性名称相似的命名字符串的特定类属性值
- python - 无法使用线性回归预测值。'float() 参数必须是字符串或数字,而不是 'datetime.datetime''
- javascript - React Native中设备连接互联网时如何将本地存储数据自动推送到服务器?