尝试使用 powermockito 模拟包私有方法时出现空指针异常
Getting nullpointer exception when trying to mock package private method using powermockito
我正在使用 mockito 和 powermockito 为以下控制器 class 编写测试用例。
@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
。我在发生空异常的测试 class 中添加了注释。
parseJwt
方法是封装private
方法。
我还尝试如下模拟 parseJwt 方法
PowerMockito.doNothing().when(classUnderTest, "parseJwt", anyString(), anyString());
然后 parseJwt
方法 return IllegalArgumentException
异常。
我想 return 从 parseJwt(jwt, key)
方法中声明等于 "Expired JWT"。
我认为错误与可见性无关public/package/private
Jwts jwts = mock(Jwts.class);
Mockito.when(jwts.parser().someMethod().someOtherMethod()...
因为 jws 是一个模拟所有模拟的方法return 类型特定的默认值(null、0 或 false)
所以如果您不添加像
这样的代码,jwts.parser() 将 return 为 null
Mockito.when(jwts.parser()).thenReturn(new MyParser());
或者您可以使用
Mockito.when(jwts.parser().thenThrow(new ExpiredJwtException(null,null,null));
我正在使用 mockito 和 powermockito 为以下控制器 class 编写测试用例。
@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
。我在发生空异常的测试 class 中添加了注释。
parseJwt
方法是封装private
方法。
我还尝试如下模拟 parseJwt 方法
PowerMockito.doNothing().when(classUnderTest, "parseJwt", anyString(), anyString());
然后 parseJwt
方法 return IllegalArgumentException
异常。
我想 return 从 parseJwt(jwt, key)
方法中声明等于 "Expired JWT"。
我认为错误与可见性无关public/package/private
Jwts jwts = mock(Jwts.class);
Mockito.when(jwts.parser().someMethod().someOtherMethod()...
因为 jws 是一个模拟所有模拟的方法return 类型特定的默认值(null、0 或 false)
所以如果您不添加像
这样的代码,jwts.parser() 将 return 为 null Mockito.when(jwts.parser()).thenReturn(new MyParser());
或者您可以使用
Mockito.when(jwts.parser().thenThrow(new ExpiredJwtException(null,null,null));