Runtime exceptions in Java 8 function - java

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".

Related

Unable to mock System class static method using PowerMockito

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();
}
}

Mockito throw exception for KafkaTemplate.send using thenThrow

I'm testing following function.
public boolean produceNumberOfPeople(NumberOfPeopleInPlaceDTO numberOfPeopleInPlaceDTO) {
final ProducerRecord<Integer, Integer> record = new ProducerRecord<>(
KafkaConfig.NUMBER_OF_PEOPLE_BY_PLACE_TOPIC,
numberOfPeopleInPlaceDTO.getId(),
numberOfPeopleInPlaceDTO.getNumberOfPeople());
try {
kafkaTemplate.send(record).get(2, TimeUnit.SECONDS);
return true;
}
catch (ExecutionException | TimeoutException | InterruptedException e) {
return false;
}
}
Here is test code.
#Test
public void produceNumberOfPeopleTest() throws InterruptedException, ExecutionException, TimeoutException {
NumberOfPeopleInPlaceDTO numberOfPeopleInPlaceDTO = NumberOfPeopleInPlaceDTO.builder()
.id(1)
.numberOfPeople(10)
.build();
Mockito.when(kafkaTemplate.send(Mockito.any(ProducerRecord.class)))
.thenReturn(listenableFuture);
Mockito.when(listenableFuture.get(2,TimeUnit.SECONDS))
.thenThrow(TimeoutException.class);
Assert.assertFalse(placeService.produceNumberOfPeople(numberOfPeopleInPlaceDTO));
}
And I defined following variables.
#Autowired
private PlaceService placeService;
#MockBean
private PlaceRepository placeRepository;
#MockBean
private KafkaTemplate<Integer, Integer> kafkaTemplate;
#MockBean
private ListenableFuture listenableFuture;
The problem is that kafkaTemplate.send(record).get(2,TimeUnit.SECONDS) doesn't throw exception. So test keep failing.
Please advice anything I 'm missing.
I will recommend to create failed ListenableFuture object with exception instead of Mock
SettableListenableFuture<SendResult<String, Object>> future = new SettableListenableFuture<>();
future.setException(new RuntimeException())
And then just return this in mock
Mockito.when(kafkaTemplate.send(Mockito.any(ProducerRecord.class))).thenReturn(listenableFuture);
So when the get method is called it throws ExecutionException
This method returns the value if it has been set via set(Object), throws an ExecutionException if an exception has been set via setException(Throwable), or throws a CancellationException if the future has been cancelled.
I am glad you solved by passing the instances to the constructor.
However, instead of creating a proper constructor, and instantiate the placeService in the test method itself, I would use another approach.
As best practice, it is recommendable to have specific setXXX methods to pass the instances, for example in your case, in PlaceService class you should have something like this:
public void setListenableFuture(ListenableFuture listenableFuture) {
this.listenableFuture = listenableFuture;
}
public void setKafkaTemplate(KafkaTemplate<Integer, Integer> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
Then, you can invoke them either in your test method (in your case produceNumberOfPeopleTest) or, even better in a specific setUp one, like this:
#Before
public void setUp() throws Exception {
placeService.setListenableFuture(listenableFuture);
placeService.setKafkaTemplate(kafkaTemplate);
}
In this way, you can leave Mock objects and placeService as members of your test class, so that JUnit and Spring Runner will have the responsibility of instantiating those objects and inject them in placeService, then you can just customize the mock behaviours each test methods you will write, according to your needs.
In my experience, I found this quite helpful, as each object involved does its proper job. Even in terms of test implementation and maintainability, you will not have to repeat the same code at each test method. For example, think about what could happen if at the certain point you have to change that constructor, in that case you will have to change all methods where you used it as well. Don't you think?
The problem was that PlaceService was not using the mock instance of KafkaTemplate. So I passed mock instance to the constructor of PlaceService manually. Now test is passed.
Here is new test code.
#Test
public void produceNumberOfPeopleTest() throws InterruptedException, ExecutionException, TimeoutException {
NumberOfPeopleInPlaceDTO numberOfPeopleInPlaceDTO = NumberOfPeopleInPlaceDTO.builder()
.id(1)
.numberOfPeople(10)
.build();
PlaceService testPlaceService = new PlaceServiceImpl(null,kafkaTemplate);
SettableListenableFuture<SendResult<String, Object>> future = new SettableListenableFuture<>();
future.setException(new RuntimeException());
Mockito.when(kafkaTemplate.send(Mockito.any(ProducerRecord.class))).thenReturn(future);
Assert.assertFalse(testPlaceService.produceNumberOfPeople(numberOfPeopleInPlaceDTO));
}

In Junit, how to prevent from printing expected exception which is thrown intentionally and caught already in log?

I guess this is a junit and Logback problem. In my project, Logging is done through slf4j. The logging implementation is Logback.
So I have a class:
#Component
#Slf4j
public class A {
private final ObjectMapper objectMapper = new ObjectMapper();
private static final String DEFAULT_REPLY = "just continue...";
public String doSomething(Object value) {
try {
return objectMapper.methodAbc(value);
} catch (JPException e) {
log.error("Exception while processing value", e);
return DEFAULT_REPLY;
}
}
}
and its test class
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Before
public void init() {
processor = new A();
}
#Test
public void test() throws Exception {
ObjectMapper mockMapper = mock(ObjectMapper.class);
JP mockJp = mock(JP.class);
Exception thrownException = new JPException(mockJp, null);
when(mockMapper.methodAbc(any())).thenThrow(thrownException);
String result = processor.doSomething("abc");
assertTrue(result.equals("just continue..."));
}
}
I don't have any problem with the test itself. Just as you can see, in the test, the JPException will be printing out on the log, because it's intentionally thrown.
When I debug through logs, there're too many this kind of expected exceptions, I'm just wondering is there a way to remove them from logs? And of course still print other exceptions which is not expected.
Logback has the functionality to support filters and evaluations based on certain logic.
This link is probably what you could be looking for :
https://logback.qos.ch/manual/layouts.html#Evaluators
You can configure your logback to do or not do certain action if it is an instance of any exceptio - in your case JPException
Try this:
Create a mock for the log.
Inject the mock into the class being tested.
Assert that the error method on the mocked log object was called.

Mockito RETURNS_SMART_NULLS answer weird behavior

I'm using the annotation #Mock(answer=Answers.RETURNS_SMART_NULL) with Mockito 1.9.5 in order to get some SmartNullPointerException when some unexpected mock calls occurs.
Unfortunately, the test pass, even without mocking at least one important call.
To be clear : My point is not to find by myself what I'm missing but to fail the test because I didn't mock the methods. I would want to do it without using Mockito.verifyNoMoreInteractions(...)
My test :
#RunWith(MockitoJUnitRunner.class)
public class ContextServiceImplTest {
#Mock(answer = Answers.RETURNS_SMART_NULLS)
private IAccountDAO accountDaoMock;
#Mock(answer = Answers.RETURNS_SMART_NULLS)
private IRuleService ruleServiceMock;
#Mock(answer = Answers.RETURNS_SMART_NULLS)
private ISensorDAO sensorDAOMock;
private ContextServiceImpl contextService;
#Before
public void before() {
contextService = new ContextServiceImpl(accountDaoMock, ruleServiceMock, sensorDAOMock);
}
#Test
public void fillSensor() throws Exception {
// given
String givenSensorId = "123"
final EventDTO givenEvent = new EventDTO();
givenEvent.setSensorId(givenSensorId)
// when
final Context context = contextService.getContext(givenEvent);
// then (should fail and throw explicit exception
}
The code to be tested :
public class ContextServiceImpl {
...
public Context getContext(final EventDTO event) throws Exception {
final String sMethodName = "getContext";
final String sensorId = event.getSensorId();
Context context = new Context();
try {
final Sensor sensor = sensorDAO.findById(sensorId);
context.setSensor(sensor);
return context;
} catch (final NoResultException nre) {
throw new BusinessException(ValidationCode.UNSUPPORTED_VALUE, "sensorId");
} catch (final PersistenceException pe) {
throw new TechnicalException(TechnicalCode.DATABASE_ACCESS_PROBLEM);
}
}
Thanks for your comments / advices / explainations.
You need to call a method on the null object sensor for the test to fail.
It seems like you are never using the null object sensor.
This means you won't get any NullPointerExceptions (smart or not)
you could do an
AssertEquals(context.getSensor().someMethod(), expectedResult);
or just a
context.getSensor().someMethod();
to get an exception.
But
AssertNotNull(context.getSensor());
won't be sufficient to get the SmartNullPointerException
Your tests will still pass because you're not invoking anything with the result of any of those mocked calls.
RETURNS_SMART_NULLS only throws a SmartNullPointerException if you attempt to dereference something that is a SmartNull. In essence, it's telling you that you're dereferencing a null value in a friendlier way, and you're not doing that with your current code.
First - you new up a Context. Unless you're getting into the weeds of threading problems, that will never come back null.
Next - you're passing in a newed EventDTO. For the same reasons above, that won't be null either.
The result of sensor may be null, but it doesn't matter - you're merely passing it through to the context without invoking any logic on it.
I'm not convinced that RETURNS_SMART_NULLS is going to work the best for your scenario. I'd recommend that you remove those answers from the mock objects. This will cause your test to fail because you haven't expected any of those interactions.

JMockit: Overriding #Mocked class

I have an internal StreamGobbler class that has 7 methods in it.
I'm looking for a quick way to mock all the methods by default, but override one method named getOutput() (e.g. Partial Mocking).
(full code not shown for clarity)
public class StreamGobbler extends Thread
{
public String getOutput()
public void run()
}
What I would like is to use something like the #Mocked annotation in combination with MockUp to partially mock the getOutput method, but retain all the "default" mocking code on all the other methods. In the docs on partial mocking, it makes the point that if you use MockUp, all non #Mock methods retain their normal functionality. Sometimes that is great, but that isn't what I want in this case.
This is similar to the question JMockit: #Mocke and MockUp combination in the same test, but I can't get away with just looking at method counts.
If I have a test setup like this:
#Test
public void execute(#Mocked StreamGobbler sg)
{
new MockUp<StreamGobbler>()
{
String type = null;
#Mock
void $init(String type)
{
this.type = type;
}
#Mock
String getOutput()
{
if ("OUTPUT".equals(type))
{
return "test output";
}
else
{
return "";
}
}
}
}
I get this error java.lang.IllegalArgumentException: Class already mocked
If I try to add the #Override annotation in the MockUp, it doesn't help (and Eclipse complains about it)
What is the best way to handle this? Use a static class outside this test method?
Using JMockit 1.17, and TestNG
In summary, how do I get every method in StreamGobbler mocked (as with #Mocked), but partially override one method (without manually doing it myself inside the MockUp?)
Full example code which meets the given constraints:
public static class StreamGobbler extends Thread {
public StreamGobbler(String type) {}
public String getOutput() { return null; }
#Override public void run() {}
}
public static class TestedClass {
public String doSomething() throws InterruptedException {
StreamGobbler sg1 = new StreamGobbler("OUTPUT");
sg1.start();
StreamGobbler sg2 = new StreamGobbler("ERROR");
sg2.start();
sg1.join(5000);
sg2.join(5000);
String output1 = sg1.getOutput();
String output2 = sg2.getOutput();
return output1 + '|' + output2;
}
}
#Test
public void useStreamGobbler(#Mocked StreamGobbler sg) throws Exception {
new Expectations() {{
new StreamGobbler("OUTPUT").getOutput(); result = "test output";
new StreamGobbler("ERROR").getOutput(); result = "";
}};
String output = new TestedClass().doSomething();
assertEquals("test output|", output);
}
Firstly, since you are creating an anonymous subclass of the MockUp class, using the #Override annotation would certainly be inappropriate. Those methods that you are providing do not belong to the MockUp class, but the generic you are providing.
Later on during runtime, (through some impressive process (based on what I read here, I'm assuming AOP)) the instance you create in this class will then use your provided method signatures instead of its own.
After reading the API on the Mock class more thoroughly as well as getting some information from JMockit's Getting Started page, I think you're issue lies in a different area entirely. If you have other test methods, they will be interfering with this method.
The error you are getting is saying: "There is already an instance of MockUp declared for the type StreamGobbler, and by calling the Mocked annotation in this test method's parameters and attempting to declare another instance of MockUp with the same generic, you are violating a JMockit stipulation."
I would check to see if you are creating an actual MockUp of StreamGobbler outside of the test method and if so (1) if you want to use it, don't redeclare another instance of MockUp in the method but continue to use the Mocked annotation or (2) if you do not want to use it and you want to re-declare a new instance of MockUp wrapping StreamGobbler, do not use the Mocked annotation in the test method's parameters but keep the MockUp instantiation.

Categories

Resources