Iam writing an application using ActiveMQ and unit test cases using Mockito where i have a asynchronous onMessage() listener and a method to test the same.The test case fails if i add any if condition in the onMessage().How to avoid this
The code snippet is as below
Main.java
//Initialize boolean here
boolean flag=false;
public void onMessage(final Message message) {
//getting error in the below if condition
if(flag) //Not executing at all Null pointer here
{
if (!(message instanceof TextMessage)) {
//Log error
}
try {
final String messageType = message.getStringProperty("messageType");
_LOG.info("The MessageType is {}", messageType);
final String msg = ((TextMessage) message).getText();
_LOG.debug(msg);
} catch (final JMSException e) {
_LOG.error("We could not read the message", e);
}
}
else //not able to execute if or else conditions
{
//do Something else
}
}
MockTest.java
//Call Main here
#InjectMocks
private Main listener;
#Test
public void shouldProcessMessage() throws JMSException {
final String messageType = "Hello";
final String messageBody ="Hi";
final ActiveMQTextMessage message = new ActiveMQTextMessage();
message.setStringProperty("messageType", messageType);
message.setText(messageBody);
// The below line does not execute at all
// iam getting null pointer exception here
listener.onMessage(message);
}
Has the Boolean value flag been instantiated somewhere in this class?
If you are getting an NPE, it's probably because you have not instantiated the flag variable.
Related
In AWS sqs i need to consider message as failed and retry it only on specific custom exception rather than on all runtime exception
#SqsListener(value = "/MyQueueURL", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS )
public void getMessageFromSqs(MyMessage message) {
log.info("message: {}", message);
// Ignore other exceptions
if(somecondition) {
throw new MyCustomException("Retry it"); //<--- Fail only on this exception
}
log.info("Success");
}
Then you need to use java try catch block, to hide the other errors. Although this concept does seem risky as ANY coding error you could lose data.
Since the deletion policy is on success it will automatically remove message from SQS.
#SqsListener(value = "/MyQueueURL", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS )
public void getMessageFromSqs(MyMessage message) {
try {
log.info("message: {}", message);
// Ignore other exceptions
if(somecondition) {
throw new MyCustomException("Retry it"); //<--- Fail only on this exception
}
log.info("Success");
} catch(Exception e) {
log.info("error")
if (e instanceOf MyCustomException) {
throw e
}
}
}
I am trying to create a unit test for my Kafka Producer which is integrated into a file. Here's my Kafka Producer:
FileName: MessageProducer.java
public boolean sendMessage(ReceivedMessage message) {
private String topicName = "output-flow";
try{
logger.info("Sending message: {} to topic: {}", message, topicName);
kafkaProducer.send(topicName, message).get();
return true;
} catch (Exception e){
logger.error("Error sending message: {} to topic: {}", message, topicName, e);
return false;
}
}
And here is what I have done so far for my unit test, obviously, with not success at all:
#Mock
private KafkaTemplate<String, ReceivedMessage > kafkaProducer;
private static final String TRANSACTION_TOPIC = "test";
// Function for parameterized values
#ParameterizedTest
#MethodSource("getTransactionProvider")
public void sendMessageTest(ReceivedMessage message) {
MessageProducer mockProducer = new MessageProducer(kafkaProducer);
when(kafkaProducer.send(TRANSACTION_TOPIC, message)).thenReturn({no idea what to put here});
when(mockProducer.sendMessage(message)).thenReturn(true);
assertTrue(mockProducer.sendMessage(message));
}
// Test for exception
// Fails too
#ParameterizedTest
#MethodSource("getTransactionProvider")
public void sendMessageTest_ThrowsException(ReceivedMessage message) {
MessageProducer mockProducer = new MessageProducer(kafkaProducer);
when(kafkaProducer.send(TRANSACTION_TOPIC, message)).thenThrow(new RuntimeException());
assertThrows(RuntimeException.class, () -> mockProducer.sendMessage(null));
}
I get Exception: org.opentest4j.AssertionFailedError: Expected java.lang.RuntimeException to be thrown, but nothing was thrown. for the latter unit test.
If I understood your question, you should return a new SendResult that would have the methods implemented with the data you expect
https://docs.spring.io/spring-kafka/api/org/springframework/kafka/support/SendResult.html
And wrap it in a Future
ListenableFuture<SendResult<K,V>>
Alternatively, make sendMessage void method (or return a Future itself), and pass in a producer callback parameter that's carried through to send, rather than making it block. Then you can assert the response of the callback
Welcome to SO...
Why does your test case fail?
Because your logic will not throw an error.
Your function will not throw an exception since you catch the exception inside the function as follow and you return boolean value.
catch (Exception e){
logger.error("Error sending message: {} to topic: {}", message, topicName, e);
return false;
}
In that case, you need to test whether the function returns false or not.
As I commented earlier, don't block the main thread by calling the get method in the future object. You can simply implement the future callbacks which can be invoked once you get the result as following
public void sendMessage(ReceivedMessage message) {
private String topicName = "output-flow";
try{
logger.info("Sending message: {} to topic: {}", message, topicName);
ListenableFuture<SendResult<String, String>> future = kafkaProducer.send(topicName, message);
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
#Override
public void onSuccess(SendResult<String, String> result) {
System.out.println("Message Sent " + result.getRecordMetadata().timestamp());
//your logic for the success scenario
}
#Override
public void onFailure(Throwable ex) {
System.out.println(" sending failed ");
// your logic if failed
throw new RuntimeException("Kafka Failed");
}
});
} catch (Exception e){
logger.error("Error sending message: {} to topic: {}", message, topicName, e);
throw new RuntimeException("Exception occurred");
}
}
UPDATE: Here's the full test:
#Test(expected = NullPointerException.class)
public void testMissingData() throws Exception{
Resource<ObjectDataModel, Content, Status> resource = builder.build(content, argA1Response,
argA2Response, objFilterParam, argA3Response);}
And here's the build method:
public Resource<ObjectDataModel, Content, Status> build(Content argContent,
ResponseA1 argA1Response,
ResponseA2 argA2Response, String argObjectTypeFilter,
ResponseA3 argA3Response) {
try {
viewDataModel.setObjectType(this.buildObjectType(filteredObjectType,
argA1Response.getData().getDataObject().getCategories().get(0).getObjectTypes().get(0)));
}
catch (Exception e) {
String msg = "Exception occoured while buildng the Object Data Model";
LOG.error(msg, e);
}
// we have the required information gathered to return
return Resource.okFromDataAndContent(viewDataModel, argContent);
}
And here's the buildObjectType() method:
private ObjectType buildObjectType(ObjectTypes argA1ProductType,
PendingObjectTypes argA2ProductType) {
ProductType objectType = new ObjectType();
List<Plan> plans = argA1ObjectType.getPlan();
List<PendingObjectSummary> objPlans = argA1ObjectType.getData();
if (objectType.getData() == null) {
objectType.setData(new ArrayList<>());
}
PendingObjectSummary tempPlan = null;
for (Plan currPlan : plans) {
tempPlan = plans.stream()
.filter(plan -> plan.getObjId().equals(currPlan.getObjId()))
.findFirst()
.orElseThrow(NullPointerException::new);
}
return objectType;
}
I'm using an Optional to test for null and I can confirm that the exception is being thrown -- but JUnit isn't catching it. Here's the test case:
#Test(expected = NullPointerException.class)
public void testMissingData() throws Exception{
Object<> response = fixture.create();
assertNotNull(response);
assertNotNull(response.getData());
assertNull(resource.getData().getObjectType());
}
In my create method I'm simply iterating over a bunch of objects to try and find one that matches my ID; if not found then throw a NullPointerException:
for (Object currObj : objects) {
tempObj = myOtherCollection.stream()
.filter(obj -> obj.getId().equals(currObj.getId()))
.findFirst()
.orElseThrow(NullPointerException::new);
}
The JUnit output clearly isn't catching the exception - here's the output:
java.lang.AssertionError: Expected exception: java.lang.NullPointerException
And my tomcat logs are definitely throwing the exception here:
18:48:30.015 [main] ERROR com.myCompany.src.ModelBuilder - Exception occoured while buildng the Data Model
java.lang.NullPointerException: null
at java.util.Optional.orElseThrow(Optional.java:290)
The only issue I can see is that maybe where I assign tempObj that the code is wrong. Am I missing anything obvious? Thanks for any helpful tips.
You are catching the nullpointer exception so the exception is not propagated to your test.
see
try {
viewDataModel.setObjectType(this.buildObjectType(filteredObjectType,
argA1Response.getData().getDataObject().getCategories().get(0).getObjectTypes().get(0)));
}
catch (Exception e) {
String msg = "Exception occoured while buildng the Object Data Model";
LOG.error(msg, e);
}
If you want to test for an exception you could throw an exception in your error handling (for example a custom ObjectCreationExcepion) and assert that that one is thrown, like
try {
viewDataModel.setObjectType(this.buildObjectType(filteredObjectType,
argA1Response.getData().getDataObject().getCategories().get(0).getObjectTypes().get(0)));
}
catch (Exception e) {
String msg = "Exception occoured while buildng the Object Data Model";
LOG.error(msg, e);
throw new ObjectCreationException(msg);
}
and in your test
#Test(expected = ObjectCreationException.class)
public void testMissingData() throws Exception{
Object<> response = fixture.create();
}
#Test(expected = ObjectCreationException.class) only handles exceptions that are not handled within the tested code OR the test itself.
So what you could do is
public Resource<ObjectDataModel, Content, Status> build(Content argContent,
ResponseA1 argA1Response,
ResponseA2 argA2Response, String argObjectTypeFilter,
ResponseA3 argA3Response) throws NullPointerExceptions // << notice thrwoing declatration
{ // do some stuf}
and then in test you can handle it like you where trying by
public void testMissingData() throws Exception{
Resource<ObjectDataModel, Content, Status> resource = builder.build(content, argA1Response,
argA2Response, objFilterParam, argA3Response);
}
I am using a bean for sending mails in my Java EE application. My class for sending mails is generated through xDoclet. Class code is given below
public void onMessage(javax.jms.Message message) {
MapMessage mapMsg = (MapMessage) message;
String toEmailAddress = mapMsg.getString("toAddress");
String ccEmailAddress = mapMsg.getString("ccAddress");
String from = mapMsg.getString("from");
String subject = mapMsg.getString("subject");
String content = mapMsg.getString("body");
}
Now, I have got some security issues in checkmarx for this class as - Deserialization of Untrusted Data in JMS at lines
String toEmailAddress = mapMsg.getString("toAddress");
String ccEmailAddress = mapMsg.getString("ccAddress");
Base on the Checkmarx query for Deserialization of Untrusted Data in JMS, add a try catch block when casting and check if message is not an instance of ObjectMessage:
public void onMessage(javax.jms.Message message) {
try {
if !(message instanceOf ObjectMessage){
MapMessage mapMsg = (MapMessage) message;
String toEmailAddress = mapMsg.getString("toAddress");
String ccEmailAddress = mapMsg.getString("ccAddress");
String from = mapMsg.getString("from");
String subject = mapMsg.getString("subject");
String content = mapMsg.getString("body");
}
}
catch {}
finally {}
}
I solved this issue in checkmarx adding the validation instanceof TextMessage in onMessage implementation:
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
....
catch (JMSException ex) {
throw new RuntimeException(ex);
}
}
else {
throw new IllegalArgumentException("Message must be of type TextMessage");
}
}
I am new to JUnit and I have to test a method using JUnit api. One method internall calls another. My test case goes inside the method but while catchign the exception it fails.
Method under test is
public void checkANDCondition( Map<String, Message> messagesMap ) throws EISClientException
{
List<String> codes = getMessageCodes();
if(isAllReturnedMessagesContainCodes(codes, messagesMap))
{
StringBuffer buff = new StringBuffer("All of the specified message codes matched returned errors.");
for(String code: codes )
{
Message message = messagesMap.get(code);
buff.append(message.getMessageCode() + ": " + message.getMessageType() + ": " + message.getMessageText() + " ");
}
throw new EISClientException(buff.toString());
}
}
public boolean isAllReturnedMessagesContainCodes(List<String> codes, Map<String, Message> messagesMap)
{
if(codes!=null)
{
for(String code: codes)
{
if(!messagesMap.containsKey(code))
{
return false;
}
}
}
return true;
}
What I have done so far is
#Test
public void testPostProcess() throws Exception {
clientResponse = mock(ClientResponse.class);
MessageToExceptionPostProcessFilter postProcessFilter = new MessageToExceptionPostProcessFilter();
RetrieveBillingServiceResponse serviceResponse = new RetrieveBillingServiceResponse();caughtException = false;
try {
postProcessFilter.setCondition(ConditionOperator.AND);
List<String> messagesCodes = new ArrayList<String>();
messagesCodes.add("200");
messagesCodes.add("400");
Message message = new Message();
message.setMessageCode("200");
message.setMessageType(MessageTypeEnum.MESSAGE_TYPE_INFO);
message.setMessageText("Service completed successfully");
serviceResponse.setMessages(Arrays.asList(message));
postProcessFilter.setMessageCodes(messagesCodes);
serviceResponse = postProcessFilter.postProcess(serviceResponse, clientResponse);
assertNotNull(serviceResponse.getMessages());
} catch (EISClientException ex) {
caughtException = true;
assertEquals("All of the specified message codes matched returned errors.", ex.getMessage());
}
assertTrue(caughtException);
}
How can I make it pass?
Thanks
#Test(expected = EISCLientException.class)
public void testPostProcess() throws Exception {
...
serviceResponse.getMessages();
fail("Shouldn't reach this point");
}
That way you don't need to catch, with expected if it does not get throw a EISClientException it will fail.
edit: There are two times I can think of where you wouldn't want to use this.
1) You are mocking exceptions that are thrown mock(exception.class);
this i believe then throws some Mockito excpetion and it will not match the expected exception.
2) You are wrapping caught exceptions in your code, and throwing a generic exception. Example of code:
try {
} catch (FileParseException e){
throw new (ProjectFailingException(e, "file is bad");
}
if you have multiple catches and are wrapping them as ProjectFailingExceptions then you may want to catch in the test like this...
#Test ( expected = FileParseException.class)
public void testProcess() {
try {
...
} catch (ProjectFailingException e){
throw e.getCause();
}
Then the proper exception is thrown and you can make sure that process isn't throwing an exception from a a different catch.