I have the following service and test methods and I am trying the code execute catch (ApplicationException e) { } block.
public abstract class ApplicationException extends RuntimeException {
// ....
}
public void create(Request request) {
try {
// ...
} catch (ApplicationException e) {
// I want the code hits this block and check the values in here
}
}
Here is the test method:
#InjectMocks
private ProductServiceImpl productService;
#Test
public void test() {
// variable defnitions and stubbings (code omitted)
willAnswer( invocation -> { throw new RuntimeException("abc msg"); })
.given(productService).create(request);
// or
// doThrow(new RuntimeException()).when(productService).create(request);
// service method call
productService.create(Request request);
}
When I debug the code, I get error on doThrow line:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
So, how can I solve the problem?
As #Jesper mentioned in comment you are not using Mockito properly.
For your test case you need to test that your ProductService.create method will handle an error in a given scenario. Let's imagine that your code looks like this.
class ProductService {
private SomeOtherService someOtherService;
public void create(Request request) {
try {
someOtherService.execute();
} catch (ApplicationException e) {
// I want the code hits this block and check the values in here
enter code here
throw new MyException(e); // Here you can do something else
}
}
So someOtherService.execute can throw ApplicationException. We need to test if our ProductService.create will catch that exception and do some processing. In the example we will just throw a different type of exception.
#Mock
private SomeOtherService mockOtherService;
#InjectMocks
private ProductServiceImpl productService;
#Test
public void test() {
doThrow(new ApplicationException()).when(someOtherService).execute();
given(productService.create(request)).willThrow(new MyException());
}
So main difference from your example is that we are telling the SomeOtherService mock what it should do when execute method is called. This is allowed and Mockito knows how to work with mocks.
In your example you were trying to pass a real object not a mock. #InjectMock annotation is a shorthand for this
this.productService = new ProductService(mockSomeOtherService);
So it creates a new object with its dependency mocked. More about this you can find here https://stackoverflow.com/a/16467893/2381415.
I didn't run this code or test it so do not C/P it.
Hope it helps you understand what was wrong with your approach.
Related
Even though I have read the manual and gone through multiple answers for Powermock, could not mock a static method for my use case.
Class:
#Component
public class SCUtil{
public void createSC(){
try {
String host = InetAddress.getLocalHost().getHostAddress();
// ...
// ...
// ...
} catch (UnknownHostException e) {
log.error("Exception in creasting SC");
throw new ServiceException(e);
}
}
}
Test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest( InetAddress.class )
public class SCUtilTest {
#InjectMocks
private SCUtil scUtil;
private Event event;
#Before
public void beforeEveryTest () {
event = new InterventionEvent();
}
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC(event);
}
}
Here, the test is failing as no exception is being thrown:
java.lang.AssertionError: Expected exception:
com.example.v1.test.selftest.errorhandling.ServiceException
I have wrecked more than a couple of hours in this and still have not gotten it to work. What am I doing wrong?
Thank you for all the help in advance :)
java.net.InetAddress is a system class. The caller of the system class should be defined in #PrepareForTest({ClassThatCallsTheSystemClass.class}).
See documentation.
The way to go about mocking system classes are a bit different than
usual though. Normally you would prepare the class that contains the
static methods (let's call it X) you like to mock but because it's
impossible for PowerMock to prepare a system class for testing so
another approach has to be taken. So instead of preparing X you
prepare the class that calls the static methods in X!
Please note #InjectMocks annotation does not inject static mocks, it can be removed.
Example of working test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(SCUtil.class)
public class SCUtilTest {
private SCUtil scUtil = new SCUtil();
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () throws UnknownHostException {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC();
}
}
My Utils class has an init method dependent upon external resources (e.g., a database connection) that I am unsuccessfully mocking with Mockito. Utils seems like it can be share across instance of my application, so is declared as a static (i.e., a class variable) in
public class EmailNotificationWorkItemHandler extends AbstractLogOrThrowWorkItemHandler {
private static Utils utils = new Utils();
public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
// Throw an error due to many missing parameters on the workitem
String id= (String) workItem.getParameter("ID");
...
try {
RequiredParameterValidator.validate(this.getClass(), workItem);
...
} catch (Throwable e) {
utils.insertErrors(id, errorCode, errorMessage, e.getStackTrace(), -1L); // testing this method called
}
...
}
I realize I could use dependency injection for Utils but am avoiding Spring. Postings about mocking static fields make me feel like I am close:
#Test
public void executeWorkItemMissingParametersTest() {
Utils mockUtils = mock(Utils.class);
WorkItemManager mockWorkItemMgr = mock(WorkItemManager.class);
EmailNotificationWorkItemHandler mockWorkItemHandler = mock(EmailNotificationWorkItemHandler.class);
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(mockUtils).insertErrors(any(), any(), any(), any(), anyLong());
try {
doAnswer(new Answer<Void>() { // Unfinished stubbing detected
public Void answer(InvocationOnMock invocation) {
return null;
}
}).when(mockUtils);
Utils.init();
} catch (Exception e) {
System.out.println("In mocking of Utils.init() " + e.getLocalizedMessage());
}
WorkItemImpl workItem = new WorkItemImpl();
workItem.setParameter("ID", "1111-AAAA");
// Lots of required parameters removed to cause an exception and insertErrors to be called
mockWorkItemHandler.executeWorkItem(workItem, mockWorkItemMgr);
verify(mockUtils).insertErrors(any(), any(), contains("RequiredParameterValidator"), any(), anyLong());
}
But a real instance of Utils is being used and called in mockWorkItemHandler - not the mocked Utils - and an "Unfinished stubbing detected" exception occurs where labeled above. My goal is to test the calling of utils.insertErrors as commented in the code and to do this without Utils' side effects. What am I missing in my mocks to (1) use a mocked Utils (without side effects, such as database connections) and (2) to test that mockWorkItemHandler's utils.insertErrors is called to record the missing parameters?
Please note that I have shown what seem to be all the relevant parts of EmailNotificationWorkItemHandler and Utils.
Here is a simple example of mocking construction calls using mockito inline. In order to enable mockito-inline you can refer to this answer since it is turned off by default by mockito. You can use this in your use case and it should fix your problem.
Consumer Class
public class ConsumerClass {
Logger logger = LoggerFactory.getLogger(ConsumerClass.class);
private static final Utils utils = new Utils();
public String callUtilMethod(){
logger.info("ConsumerClass callUtilMethod");
return utils.helloWorld();
}
}
Utils
public class Utils {
Logger logger = LoggerFactory.getLogger(Utils.class);
public String helloWorld() {
logger.info("Utils class Hello World");
return "This is from Utils";
}
}
Testcase
#Test
void testConsumerClass() {
try (MockedConstruction<Utils> mocked = Mockito.mockConstruction(Utils.class, (mock, context) -> {
Mockito.when(mock.helloWorld()).thenReturn("This is from Mock");
})) {
ConsumerClass consumerClass = new ConsumerClass();
Assertions.assertEquals("This is from Mock", consumerClass.callUtilMethod());
}
}
I'm using Java 8 Functions and converters and have the following:
Main class
public final class MainClass {
public MainClass(
final Function<InputModel, OutputModel> businessLogic,
final Converter<Input, InputModel> inputConverter,
final Converter<OutputModel, Output> outputConverter) {
this.businessLogic = requireNonNull(businessLogic, "businessLogic is null.");
this.inputConverter = requireNonNull(inputConverter, "inputConverter is null.");
this.outputConverter = requireNonNull(outputConverter, "outputConverter is null.");
}
/**
* Request Handler.
*/
public Output handleRequest(final Input input) {
requireNonNull(input, "input is null.");
log.info("input request: {}", input);
try {
return inputConverter
.andThen(businessLogic)
.andThen(outputConverter)
.apply(input);
} catch (final Exception ex) {
throw new InternalServiceException(ex.getMessage(), ex);
}
}
}
Unit test
public final class TestClass {
#Mock
private Function<InputModel, OutputModel> mockedBusinessLogic;
#Mock
private Converter<Input, InputModel> mockedInputConverter;
#Mock
private Converter<OutputModel, Output> mockedOutputConverter;
private MainClass mainClass = new MainClass(mockedBusinessLogic, mockedInputConverter, mockedOutputConverter);
#Test
public void handleRequest_SHOULD_throwException_WHEN_inputConverter_throwsException() {
final RuntimeException inputConverterException = new NullPointerException(EXCEPTION_MESSAGE);
// what should I mock here? apply or convert.. apply for `Converter` seems to be deprecated.
when(mockedInputConverter.convert(input))
.thenThrow(inputConverterException);
final Exception exception = assertThrows(
InternalServiceException.class,
() -> mainClass.handleRequest(input)
);
assertThat(exception.getMessage(), is(EXCEPTION_MESSAGE));
assertThat(exception.getCause(), is(inputConverterException));
}
}
The above assertions fail.
I expect that if the inputConverter throws an exception, the catch block in handleRequest would wrap it to InternalServiceException, but it doesn't seem to be happening.
Any help?
How do I actually write unit tests for handleRequest method? I want to test the behavior when either of inputConveter, businessLogic or outputConveter throws exception.
Everything in your code is a mock. When you call andThen on your mocked inputConverter, then either null or a new mock instance is returned (depending on configuration). Each andThen will return a new instance with the chained converters (at least that is what I assume)
Make sure you mock all required methods, or better, use real objects instantiated from real classes.
Setting breakpoints and then debugging should help you find the issue. If you set in your try-block, and then single-step through the code, you will see that the way mocks are used in your code will not work. You could also save each result of andThen in a variable and then check in the debugger what type each has. I'm pretty sure it will either be null or "Mock for class X".
I have a method that takes in the String, and check if it contains another string. If it does, then it throws a custom exception.
Class Test{
String s2="test";
public void testex(String s1){
if(s1.contains(s2))
throw new customException();
}
}
I am trying to write a unit test for this:
#Test (expected = customException.class){
when(s1.contains(s2)
.thenThrow(new customException());
}
However, my test is failing with the error as-- java.lang.Exception: Unexpected exception, expected customException but was<org.mockito.exceptions.misusing.MissingMethodInvocationException>
This test doesn't seem to be particularly useful, but I believe your issue is that Mockito's when() expects a method call for a mocked object.
#Test(expcted = CustomException.class)
public void testExMethod() {
#Mock
private Test test;
when(test.testEx()).thenThrow(CustomException.class);
test.testEx("test string");
}
I'm not quite following your example test. It looks like you're mocking your actual class with Mockito rather than writing a junit test. I would write a test like this:
With junit's assertThrows method:
#Test
void stringContainingThrowsError() {
Test myClassThatImTesting = new Test();
assertThrows(CustonException.class, () -> myClassThatImTesting.testex("test"))
}
With a normal assertion:
#Test
void stringContainingThrowsError() {
Test myClassThatImTesting = new Test();
try {
myClassThatImTesting.testex("test");
fail();
} catch (Exception ex) {
assertTrue(ex instanceof CustomException);
}
}
I am facing an issue when trying to unit test a function call. The call is failing for a void method invocation messageProducer.sendMessage() even though it has been stubbed.
Please find below a simplified snapshot of my code. I am using a doAnswer() stubbing to mock the void method (based on earlier answers on StackOverflow).
I even tried the other options of doThrow() and doNothing() stubbings, but they also fail with the same NPE when calling the stubbed method :(.
Appreciate if someone could suggest a solution/workaround. Many thanks.
Test Class
// Test class
#RunWith(MockitoJUnitRunner.class)
public class RetriggerRequestTest {
#Mock
private MessageProducer messageProducer;
#InjectMocks
private MigrationRequestServiceImpl migrationRequestService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void sendRetriggerRequest() throws Exception {
// Below two stubbings also not Work, NPE encountered!
//doNothing().when(messageProducer).sendMessage(any(), anyLong());
//doThrow(new Exception()).doNothing().when(messageProducer).sendMessage(any(), anyLong());
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(messageProducer).sendMessage(any(EMSEvent.class), anyLong());
try {
// Gets Null pointer exception
migrationRequestService.retriggerRequest(emsRetriggerRequest);
}
catch (Exception ex) {
fail(ex.getMessage());
}
}
Implementation Class being tested, the stubbed method call from this class throws NPE as indicated in code comments
#Service
#Transactional
public class MigrationRequestServiceImpl implements MigrationRequestService {
#Autowired
MessageProducer messageProducer;
#Override
public void retriggerRequest(EMSRetriggerRequestData emsRetriggerRequestData) throws EMSException {
// Does a bunch of things
submitTaskScheduledEventsToQueue(taskList);
}
private void submitTaskScheduledEventsToQueue(List<Task> taskList) {
System.out.println("Debugging 1...");
taskList.stream().forEach(task -> {
System.out.println("Debugging 2...");
Map<String, Object> detailsMap = new HashMap<String, Object>();
EMSEvent event = new EMSEvent(EMSEventType.TASK_SCHEDULED);
event.setDetails(detailsMap);
LOGGER.info(ContextRetriever.getServiceContext(), ContextRetriever.getRequestContext(), "*** Re-submitting Task: *** " + task.getId());
// ****Gives a null pointer exception here****
messageProducer.sendMessage(event, eventsConfigProperties.getScheduledEventDelay());
});
System.out.println("Debugging 3...");
}
}
Autowired class that is injected into the test class and whose method is throwing the NPE
#Service
public class MessageProducer {
private static final Logger logger = LoggerFactory.getLogger(MessageProducer.class);
private final RabbitTemplate rabbitTemplate;
#Autowired
public MessageProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void sendMessage(EMSEvent emsEvent, Long delay) {
// code to send message to RabbitMQ here
}
}
Do not use doAnswer if you simply want to capture the arguments and process/verify them in some way. Mockito has a defined feature called ArgumentCaptor that is designed just for that. By using it you will not need to haggle around with that void method the way you do:
#Mock private MessageProducer messageProducer;
#Captor private ArgumentCaptor<Event> eventCaptor;
#Captor private ArgumentCaptor<Long> longCaptor;
#InjectMocks
private MigrationRequestServiceImpl migrationRequestService;
#Test
public void sendRetriggerRequest() throws Exception {
// When
migrationRequestService.retriggerRequest(emsRetriggerRequest);
// Then
verify(messageProducer).sendMessage(eventCaptor.capture(), longCaptor.capture());
Event e = eventCaptor().getValue();
Long l = longCaptor().getValue();
}
Thank you Maciej for the answer. Actually I don't want to do anything with the arguments, I just need to skip this method call. I just used doAnswer with some dummy code since doNothing() or doThrow() did not work with this method.
I was able to resolve the issue however. One of the Autowired components (eventsConfigProperties) for the class which was being injected with Mocks (MigrationRequestServiceImpl) was not being mocked in the test class! Thanks to #daniu for pointing this out.
The stack trace from Mockito was not very helpful in debugging the issue, it just gave a null pointer exception right on the method invocation which caused me to think there may be other issues!
Apologize for the mistake, my bad, but thank you and good to know about the ArgumentCaptor, would probably need it for future testing!
Had to add this entry which was autowired into the MigrationRequestService class.
// Test class
#RunWith(MockitoJUnitRunner.class)
public class RetriggerRequestTest {
#Autowired
EventsConfigProperties eventsConfigProperties;
// Other declarations
}