I'm trying to write a unit test case for the handler.sendRequest(request); function. However, it returns the null pointer exception.
When I print the request object in the unit test it returns null. However, I have initialized the request object not sure why it is giving null pointer exception. Is something wrong with the Data object? Have I missed something? Can someone please help? Thanks!
public class ServicesHandlerTest {
#Mock
private RestTemplate restTemplate;
#Mock
private ObjectMapper mapper;
#Mock
private AuthHandler AuthHandler;
#InjectMocks
ServicesHandler handler;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#After
public void tearDown() throws Exception {
}
#Test
public void testSuccess() throws Exception {
Data data = new Data();
data.setRequestId(UUID.randomUUID().toString());
data.setRequestedQuantity(10);
Request request = new Request();
request.setData(data );
System.out.println("request = " + request);
ServicesHandler handler = new ServicesHandler();
Mockito.when(AuthHandler.requestToken()).thenReturn("randomString");
Mockito.when(msAuthHandler.createAuthorizationBearerHttpHeaders("randomString")).thenReturn(any());
Mockito.when(restTemplate.postForEntity(anyString(), any(), eq(String.class))).thenReturn(new ResponseEntity<String>(HttpStatus.OK));
handler.sendRequest(request);
}
#Component
public class ServicesHandler extends AbstractHandler {
#Value("${api.host}")
private String msApiHost;
#Value("${base.path}")
private String BasePath;
#Autowired
private AuthHandler authHandler;
public AuthHandler getAuthHandler() {
return authHandler;
}
public ResponseEntity<String> sendRequest(Request pr) throws Exception {
ResponseEntity<String> response = null;
try {
String requestToken = getAuthHandler().requestToken();
HttpHeaders headers = getAuthHandler().createAuthorizationBearerHttpHeaders(requestToken);
String apiUrl = ApiHost + BasePath;
RestTemplate restTemplate = new RestTemplate();
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
HttpEntity<Request> request = new HttpEntity<Request>(pr, headers);
response = restTemplate.postForEntity(apiUrl, request, String.class);
} catch (HttpStatusCodeException e) {
logger.error("Error when sending for provisioning " + e.getResponseBodyAsString(), e);
return ResponseEntity.status(e.getStatusCode()).body(e.getResponseBodyAsString());
} catch (Exception e) {
throw e;
}
return response;
}
}
public class Data {
private String requestId;
private Integer requestedQuantity;
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public Integer getRequestedQuantity() {
return requestedQuantity;
}
public void setRequestedQuantity(Integer requestedQuantity) {
this.requestedQuantity = requestedQuantity;
}
}
It gives me an error in getAuthHandler().requestToken(); function inside handler.sendRequest(request);
Below is the stacktrace:
java.lang.NullPointerException at com.xyz.abc.sendRequest(ServicesHandler.java:443) at com.xyz.abc.ServicesHandlerTest.testSuccess(ServicesHandlerTest.java:150) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498)
You should inject the mocks into ServicesHandler using #InjectMocks, see the docs for more information MockitoAnnotations.initMocks
public class ServicesHandlerTest {
#InjectMocks
private ServicesHandler;
#Mock
private RestTemplate restTemplate;
#Mock
private ObjectMapper mapper;
#Mock
private AuthHandler AuthHandler;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#After
public void tearDown() throws Exception {
}
#Test
public void testSuccess() throws Exception {
Data data = new Data();
data.setRequestId(UUID.randomUUID().toString());
data.setRequestedQuantity(10);
Request request = new Request();
request.setData(data );
System.out.println("request = " + request);
Mockito.when(AuthHandler.requestToken()).thenReturn("randomString");
Mockito.when(restTemplate.postForEntity(anyString(), any(), eq(String.class))).thenReturn(new ResponseEntity<String>(HttpStatus.OK));
handler.sendRequest(request);
}
}
Related
I have a Service class, which makes 2 different calls to another API which returns 2 different response objects. For Simplicity let that be shown as below
public class Service {
public AddResponseWrapper add(Request request) {
final AddResponseWrapper addResponseWrapper = new AddResponseWrapper();
try {
final AddResponse addResponse = addApi.add(request);
addResponseWrapper.setAddResponse(addResponse);
} catch (final Exception e) {
addResponseWrapper.setErrorDetails(convert(e));
}
return addResponseWrapper;
}
public DeleteResponseWrapper delete(Request request) {
final DeleteResponseWrapper deleteResponseWrapper = new DeleteResponseWrapper();
try {
final DeleteResponse deleteResponse = deleteApi.delete(request);
deleteResponseWrapper.setDeleteResponse(deleteResponse);
} catch (final Exception e) {
deleteResponseWrapper.setErrorDetails(convert(e));
}
return deleteResponseWrapper;
}
}
Similarly, I have these 2 below POJOs created
public class AddResponseWrapper {
private AddResponse addResponse;
private ErrorDetails errorDetails;
public AddResponse getAddResponse() {
return addResponse;
}
public void setAddResponse(final AddResponse addResponse) {
this.addResponse = addResponse;
}
public ErrorDetails getErrorDetails() {
return errorDetails;
}
public void setErrorDetails(final ErrorDetails errorDetails) {
this.errorDetails = errorDetails;
}
}
public class DeleteResponseWrapper {
private DeleteResponse deleteResponse;
private ErrorDetails errorDetails;
public DeleteResponse getDeleteResponse() {
return deleteResponse;
}
public void setDeleteResponse(final DeleteResponse deleteResponse) {
this.deleteResponse = deleteResponse;
}
public ErrorDetails getErrorDetails() {
return errorDetails;
}
public void setErrorDetails(final ErrorDetails errorDetails) {
this.errorDetails = errorDetails;
}
}
The AddResponseWrapper & DeleteResponseWrapper are classes that I have created, while the AddResponse and DeleteResponse classes are classes that I inherit from the API that I call.
Now if I make 2 more APi calls, for say Subtract & Multiply operations, I would have to create 2 more POJO classes SubtractResponseWrapper and MultiplyResponseWrapper.
I do not find this solution clean, what I would really like to have is a Generic class, that should be returned from each of these calls and I can avoid the use of multiple Pojo classes.
Try this - however without some sort of heirarchy in your response objects it's possibly going to be not much better than ResponseWrapper<Object>.
public class ResponseWrapper<T> {
private T response;
private ErrorDetails errorDetails;
public T getResponse() {
return response;
}
public void setResponse(final T response) {
this.response = response;
}
public ErrorDetails getErrorDetails() {
return errorDetails;
}
public void setErrorDetails(final ErrorDetails errorDetails) {
this.errorDetails = errorDetails;
}
}
Then your service becomes -
public class Service {
public ResponseWrapper<AddResponse> add(Request request) {
final ResponseWrapper<AddResponse> addResponseWrapper = new ResponseWrapper<AddResponse>();
try {
final AddResponse addResponse = addApi.add(request);
addResponseWrapper.setResponse(addResponse);
} catch (final Exception e) {
addResponseWrapper.setErrorDetails(convert(e));
}
return addResponseWrapper;
}
public ResponseWrapper<Delete> delete(Request request) {
final ResponseWrapper<Delete> deleteResponseWrapper = new ResponseWrapper<Delete>();
try {
final DeleteResponse deleteResponse = deleteApi.delete(request);
deleteResponseWrapper.setResponse(deleteResponse);
} catch (final Exception e) {
deleteResponseWrapper.setErrorDetails(convert(e));
}
return deleteResponseWrapper;
}
}
Without changing the API class you can't go much further on simplification.
Can I somehow use doAnswer() when an exception is thrown?
I'm using this in my integration test to get method invocations and the test in configured the #RabbitListenerTest...
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyIT {
#Autowired
private RabbitTemplate rabbitTemplate;
#Autowired
private MyRabbitListener myRabbitListener;
#Autowired
private RabbitListenerTestHarness harness;
#Test
public void testListener() throws InterruptedException {
MyRabbitListener myRabbitListener = this.harness.getSpy("event");
assertNotNull(myRabbitListener);
final String message = "Test Message";
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(1);
doAnswer(answer).when(myRabbitListener).event(message);
rabbitTemplate.convertAndSend("exchange", "key", message);
assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
verify(myRabbitListener).messageReceiver(message);
}
#Configuration
#RabbitListenerTest
public static class Config {
#Bean
public MyRabbitListener myRabbitListener(){
return new MyRabbitListener();
}
}
}
It works ok but when I introduce an Exception being thrown, It doesn't i.e
This works
#RabbitListener(id = "event", queues = "queue-name")
public void event(String message) {
log.info("received message > " + message);
}
This doesn't
#RabbitListener(id = "event", queues = "queue-name")
public void event(String message) {
log.info("received message > " + message);
throw new ImmediateAcknowledgeAmqpException("Invalid message, " + message);
}
Any help appreciated
The LatchCountDownAndCallRealMethodAnswer is very basic
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
invocation.callRealMethod();
this.latch.countDown();
return null;
}
You can copy it to a new class and change it to something like
private volatile Exception exeption;
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
try {
invocation.callRealMethod();
}
catch (RuntimeException e) {
this.exception = e;
throw e;
}
finally {
this.latch.countDown();
}
return null;
}
public Exception getException() {
return this.exception;
}
then
assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
assertThat(answer.getException(), isInstanceOf(ImmediateAcknowledgeAmqpException.class));
Please open a github issue; the framework should support this out-of-the-box.
I am using Apache Camel + SpringBoot + JDBC.I would like to do JUnit testing for end to end camel routes.My Processor is having DB Calls with Logic.But I am struggling to remove DB calls mocking to achieve testing.My junit is working but I dont know how to mock the JDBC object inside of my processor.I have lots of boiler plate code in my processors so I don't want to duplicate my logic inside of junits as I have done in this junit example.Please help me to solve this.
Applicaiton.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
MyRouter.java
#Component
public class MyRouter extends RouteBuilder {
#Autowired
OrderProcessor processor;
#Override
public void configure() throws Exception {
from("file://src/main/resources/input?delete=true&moveFailed=.error").routeId("route1").convertBodyTo(byte[].class)
.process(processor).split(simple("${body}")).to("file://src/main/resources/output?fileName=outputfile.txt&fileExist=Append");
}
}
OrderProcessor.java
#Component
public class OrderProcessor implements Processor{
#Autowired
DataSource dataSource;
#Autowired
OrderRepository repository;
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("process starts...");
byte[] data = exchange.getIn().getBody(byte[].class);
File dataFile = File.createTempFile("filepre", "bin");
FileUtils.writeByteArrayToFile(dataFile, data);
List<String> orders = new ArrayList<>();
FileReader fileReader = new FileReader(dataFile);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
line = line.substring(line.length()-1);
orders.add(repository.getOrder(line).toString()+"\n");
}
fileReader.close();
exchange.getIn().setBody(orders);
}
}
Order.java
public class Order {
private int id;
private int amount;
// getters and setters
#Override
public String toString() {
return this.id + ":" + this.amount;
}
}
OrderRepository.java
#Repository
public class OrderRepository {
#Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
public Order getOrder(String id) {
Map<String, Object> parameters = new HashMap<>();
parameters.put("refid", id);
Order extObj = jdbcTemplate.query("select * from world.orders where id = :refid",parameters, rs -> {
Order innerObj = null;
if (rs != null) {
while (rs.next()) {
innerObj = new Order();
innerObj.setId(rs.getInt("id"));
innerObj.setAmount(rs.getInt("amount"));
}
}
return innerObj;
});
return extObj;
}
}
jUnit Class:
public class MyRouterTest extends CamelSpringTestSupport {
#Override
protected AbstractApplicationContext createApplicationContext() {
return new AnnotationConfigApplicationContext();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file://src/test/resources/input?delete=true&moveFailed=.error").routeId("route1")
.convertBodyTo(byte[].class).process(exchange -> {
Map<String, Integer> mockValues = new HashMap<>();
mockValues.put("1", 8);
mockValues.put("2", 10);
mockValues.put("3", 5);
System.out.println("process starts...");
byte[] data = exchange.getIn().getBody(byte[].class);
File dataFile = File.createTempFile("filepre", "bin");
FileUtils.writeByteArrayToFile(dataFile, data);
List<String> orders = new ArrayList<>();
FileReader fileReader = new FileReader(dataFile);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
line = line.substring(line.length() - 1);
Order orderTmp = new Order();
orderTmp.setId(Integer.parseInt(line.substring(line.length() - 1)));
orderTmp.setAmount(mockValues.get(line.substring(line.length() - 1)).intValue());
orders.add(orderTmp.toString() + "\n");
}
fileReader.close();
exchange.getIn().setBody(orders);
}).split(simple("${body}"))
.to("file://src/test/resources/output?fileName=outputfile.txt&fileExist=Append");
}
};
}
#Test
public void checkFileExistsInOutputDirectory() throws InterruptedException {
Thread.sleep(15000);
File file = new File("src/test/resources");
assertTrue(file.isDirectory());
// Check file content
}
}
inputfile.txt
line1
line2
line3
outputfile.txt
1:8
2:10
3:5
I think that you are trying to test too much, processor logic is not in the scope of MyRouter class, so you should use a mock. Tests for processor should be done separately.
My advice:
create mock of OrderProcessor
inject mock of OrderProcessor to real implementation of MyRouter
pass MyRouter instance (with mocked processor inside) to createRouteBuilder method in test
call route in tests
With Mockito it should be quite easy:
public class MyRouterTest extends CamelTestSupport {
#Mock
private OrderProcessor orderProcessor;
#InjectMocks
private MyRouter myRouter;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks( this );
super.setUp(); //important
doAnswer( invocation -> {
Exchange exchange = invocation.getArgumentAt( 0, Exchange.class );
//mock processor logic;
return null;
} ).when( orderProcessor ).process( any() );
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return myRouter;
}
#Test
public void testYourStuff() {
}
}
Can anyone suggest me how to write JUnit for the below class:
#Controller
#RequestMapping(value = "/cutdata", consumes = "TEXT/XML")
public class CustController
{
Logger LOG = Logger.getLogger(CustController.class);
#Autowired
CustService custService;
#Autowired
MarCusService marCustService;
#Resource(name = "CustValidator")
private CusValidator validator;
#Resource(name = "cmsSiteService")
private CMSSiteService cmsSiteService;
protected CMSSiteService getCmsSiteService()
{
return cmsSiteService;
}
#RequestMapping(value = "/methodcall", method = RequestMethod.PUT)
public #ResponseBody ResponseEntity<?> methodCall(#RequestBody final CustDTO data)
throws WebServicesException
{
String statusCode = null;
try {
if (data.getGroup() != null && !data.getGroup().equals(String.valueOf(GroupEnum.ALL))) {
validator.validate(data);
}
} catch (WebServicesException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.OK);
}
try
{
final CMSSiteModel site = cmsSiteService.getCurrentSite();
String currentSiteId=site.getUid() !=null ? site.getUid():"";
if(StringUtils.contains(currentSiteId,Config.getParameter("****.siteuid")))
{
statusCode = marCustService.processData(data);
}
else
{
statusCode = custService.processData1(data);
}
final String[] message = statusCode.split(":");
final String code = message[0];
final String statusMessage = message[1];
if (code.equalsIgnoreCase("200"))
{
return new ResponseEntity<>(statusMessage, HttpStatus.CREATED);
}
else if (code.equalsIgnoreCase("400"))
{
return new ResponseEntity<>(statusMessage, HttpStatus.BAD_REQUEST);
}
}
catch (final Exception e)
{
LOG.error("log ::" + e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I'm new in writing JUnit Test case, i need help like how to write or how to start JUnit.
Basically, you need to make use of the Spring context to test Controller classes.
One example would be something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class CsrfShowcaseTests {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
public void shouldTestMethodCall() {
mockMvc.perform(put("/methodcall"))
.andExpect(status.isOk());
}
}
From this test you can expand the testing to whatever your flows are.
If you need more references, you can check Spring's documentation here.
My project uses spring framework
WebSocketConfig.java
#Configuration
#EnableWebMvc
#EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor());
registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
.withSockJS();
}
#Bean
public WebSocketHandler systemWebSocketHandler(){
return new SystemWebSocketHandler();
}
}
SystemWebSocketHandler.java
public class SystemWebSocketHandler implements WebSocketHandler {
private static final Logger logger;
private static final ArrayList<WebSocketSession> users;
static {
users = new ArrayList<>();
logger = LoggerFactory.getLogger(SystemWebSocketHandler.class);
}
#Autowired
private WebSocketService webSocketService;
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.debug("connect to the websocket success......");
users.add(session);
String userName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
//查询未读消息
int count = webSocketService.getUnReadNews((String)session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
session.sendMessage(new TextMessage(count+""));
}
#Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
}
#Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
logger.debug("websocket connection closed......");
users.remove(session);
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
logger.debug("websocket connection closed......");
users.remove(session);
}
#Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有在线用户发送消息
*
* #param message
*/
public void sendMessageToUsers(TextMessage message) {
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 给某个用户发送消息
*
* #param userName
* #param message
*/
public void sendMessageToUser(String userName, TextMessage message) {
for (WebSocketSession user : users) {
if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
}
my jsp client
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/Origami/webSocketServer");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost:8080/Origami/webSocketServer");
} else {
websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");
}
this is my websocket code and it works well
now I want to send messages to the client in a controller ,this is my controller
#Controller
public class AdminController {
static Logger logger = LoggerFactory.getLogger(AdminController.class);
#Autowired(required = false)
private AdminService adminService;
#Autowired(required = false)
private SystemWebSocketHandler systemWebSocketHandler;
#RequestMapping("/auditing")
#ResponseBody
public String auditing(HttpServletRequest request){
String result = "fail";
int id = Integer.parseInt(request.getParameter("id"));
String reason = request.getParameter("reason");
String title = request.getParameter("title");
String username = request.getParameter("username");
News news = new News();
DateTime dateTime = DateTime.now();
news.setNewsTime(dateTime.toDate());
news.setState(0);
news.setUsername(username);
if(reason.equals("")){
result = adminService.auditingById(id,"Y");
news.setNewsContent(String.format(Constants.AUDIT_MESSAGE, username, title, reason));
adminService.addNewsWithUnAudit(news);
}else{
news.setNewsContent(String.format(Constants.UN_AUDIT_MESSAGE,username,title,reason));
result = adminService.addNewsWithUnAudit(news);
result = adminService.auditingById(id, "D");
}
//SystemServerEndPoint serverEndPoint = new SystemServerEndPoint();
int unReadNewsCount = adminService.getUnReadNews(username);
systemWebSocketHandler.sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
return result;
}
}
I want to call
systemWebSocketHandler.sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
to send message to the client but systemWebSocketHandler is null
How to inject the systemWebSocketHandler to the controller
or some other ideas to complete the required? Such as the server connect to the websocketserver when it need to send message to the client and closed when it finished
My English is poor, but I'm trying to learn
I have resolved the problem
#Controller
public class AdminController {
#Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}