Junit test - Eclemma Coverage in Jackson toString - java

I want to have 100% coverage on the method toString overriden with Jackson JSON.
#Override
public String toString() {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
logger.error(e.getMessage());
return "";
}
}
I can make a test that can coverage the most of the code except the catch block.
#Test
public void testToString() {
TestClass testClass = new TestClass();
String expected = "{\"testAttr\":null}";
assertEquals(expected, testClass.toString());
}
How could I make a test that covers the catch block?

Of course you cold try to trigger that exception somehow with setting the enclosing object to some weird kind of state. But a better way to achieve full code coverage is mocking the mapper and making it throw the desired exception. Generally the steps that you need are:
Transfer the creation of ObjectMapper to a new method 'getObjectMapper'. During runtime it will decide if it returns a real or a fake mapper.
In your test inject a fake ObjectMapper and make 'getObjectMapper' return the fake mapper instead of a new mapper.
When the writeValueAsString method is called make it throw a JsonProcessingException
Run your test
In theory you could manually create the fake ObjectMapper e.g. by creating a subclass of it but that's not the recommended way. I would recommend using a mocking framework. A mocking framework lets you express things like "when method A is called then throw exception B".

You can define some attributes to your class and assert the return of the string.
You've already tested the null object.
Raise the exception and see if it handles it.
Like:
when(mapper.writeValueAsString(any(Object.class))).thenThrow(new JsonProcessingException("Error"){});
And also helpful link

Related

Mockito - Mock dependency without injection

I've been looking at forums all day trying to mock a class, but none of the solutions have worked for me, and I have no clue what I'm doing wrong (I'm new to Java testing).
I have this (renamed) class that I want to test, mainly each if condition to ensure they work:
public class MyClass {
public static List<Object> MyClass(#NotNull Session session, #NotNull MyObject updated, #NotNull Mode mode)
throws Exception {
ModeList modes = MyUtil.geModes(mode);
try {
final Transaction tr = updated.getTransaction();
MyObject original;
if(tr == null) {
original = new Foo().getCurrentBar(session, updated.getKey(), null, "en");
} else {
original = new Foo().getOtherBar(session,
updated.getKey(),
tr.getProp1().intValue(),
tr.getProp2().intValue(),
"en");
}
return SomeClass.check(updated, original, modes);
} catch (Exception ex) {
// handle
}
return null;
}
}
Please note I can't change this (or the Foo class) / add dependency injection, it needs to be tested as is. I have tried mockito, powerMock mock, mockStatic, partial mocks, etc, they all fail for one reason or another, and the real getCurrentBar / getOtherBar get called.
I may be getting tunnel vision at this point, but please advise.
This code is wrong, it should use a factory to get Foo, so you can mock the factory. But since you can't modify it then the next best thing is to use PowerMock.
You can follow this guide: https://github.com/powermock/powermock/wiki/MockConstructor make sure you do not forget the #RunWith and #PrepareForTest annotations.

How to trigger JsonProcessingException for Java Unit Test?

I have a method in a class called "HttpResponseHelper" that I am trying to Unit Test when it throws a JsonProcessingException, but I was having difficulties getting it do so:
private static void populateHTTPResponseWithData(ObjectNode httpResponse)
{
ObjectMapper mapper = new ObjectMapper();
responseMapData.keySet().forEach(item -> {
try
{
httpResponse.put(item, mapper.writeValueAsString(responseMapData.get(item)));
}
catch (JsonProcessingException e)
{
LOGGER.error("Json Processing Exception", e);
}
});
}
The httpResponse argument is type ObjectNode (Jackson library), and then inside the method body a mapper object is created from the ObjectMapper class.
The resonseMapData is a ConcurrentHashMap> from a class called "MessageProcessResults". It looks like here its looping through the keySet and inserting a String for the Key Value pair inside of the httpResponse argument.
I tried using mockito on mapper to return a malformed JSON, but it looks like it writes the value as a String and passes each time.
Does anyone have any suggestions or is there a simple way to do this? Thank you for taking the time to read this question and possibly help me :D
You can also extend JsonProcessingException for your tests:
private static class MockJsonProcessingException extends JsonProcessingException {
public MockJsonProcessingException(String message) {
super(message);
}
}
And then in your test:
var exception = new MockJsonProcessingException("Because of protected constructors");
when(objectMapper.writeValueAsString(thing)).thenThrow(exception);
EDIT: Note this assumes you're using dependency injection and injecting a mock ObjectMapper into your object, as is necessary to make this case testable.
The #HarryQ answer wont work as JsonProcessingException has a package protected constructor.
For those methods that throw this you can use InputCoercionException. It extends from JsonProcesssingException and allows something like, ugly, yeah I know, but it works:
when(mockObjectMapper.writeValueAsString(any())).thenThrow(new InputCoercionException(null, "my mock exception", null, null));
When you are doing unit test, you don't focus on how the underlying code would create an exception, but how your code deal with such an exception. In that regards, you can mock the ObjectNode object, and ask it to throw an exception whenever put method is called.
#Test
public void someTest(){
Object mockObject = Mockito.mock(ObjectNode.class);
Mockito.when(mockObject.put()).thenThrow(new JsonProcessingException ("my mock exception"));
functionUndertest(mockObject); //this is where you inject your mock function. In your case you are expecting a error message to be printed.
}

Infinite recursion when deserializing with Jackson and Mockito

I am trying to generically print any object with mapper.writeValueAsString but I am facing a infinite recursion when deserializing objects with Mockito and Jackson. The objects I am trying to deserialize perform underlying Hibernate calls to DBs etc and I have no control over the classes themselves.
Currently I am using the following versions of Mockito and Jackson but the same is happening for older 1.X versions of Jackson.
Mockito: org.mockito:mockito-all:jar:1.9.5:compile
Jackson: com.fasterxml.jackson.core:jackson-databind:jar:2.9.7:compile
As specified, I cannot modify the underlying classes with annotation such as #JsonIgnore because they are outside dependencies not under my control. I also cannot create mixins for my user case because I am trying to generically print the contents of any object that is sent in.
I have tried adding the DeserializationConfig FAIL_ON_UNKNOWN_PROPERTIES to false in older Jackson version and I have tried setting the DeserializationFeature FAIL_ON_MISSING_CREATOR_PROPERTIES to false.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public static PrintUtil {
public static String printJSON(Object obj) {
String printstring = "printfailed";
try {
ObjectMapper mapper = new ObjectMapper();
LOG.debug("formatted JSON String ");
printstring = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return printstring;
}
}
The infinite recursion terminal output is seen when running Mockito tests for methods that contain Log4j statements which in turn call the PrintUtil function. The statement e.printStackTrace() begins printing while running the tests.
Most of the object that are being sent to this utility method are JAXB XML Service Response Objects.
Without being able to modify the classes themselves, I see two possible solutions.
1) Wrap the objects into objects you own as suggested by #TheHeadRush and annotate it appropriately. I would suggest using #JsonIdentityInfo so the objects serialize to their ID, rather than being ignored completely with #JsonIgnore.
2) Use a custom deserializer for the object which is causing the recursion. Here is an example:
public class CustomDeserializer extends StdDeserializer<MyObject>{
// Add constructors as necessary.
#Override
public List<Item> deserialize(
JsonParser jsonparser,
DeserializationContext context)
throws IOException, JsonProcessingException {
return null; // Return something that won't recurse here.
}
}
Then register the deserializer with the ObjectMapper you are using:
// Register the deserializer:
SimpleModule module = new SimpleModule()
.addDeserializer(MyObject.class, new CustomDeserializer());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);

Mockito mock method based on another mock method

Let's say that I have a some service class
class Service<T> {
T get(int id);
void save();
}
In my unit tests I mock both methods of this service using mockito. But there is a case when method save should be mocked based on mocked get method. For example if method get is called with an argument which is equal to 2 then method save should throw some exception.
I went through Mockito documentation but seems like have not found any solutions yet.
Any ideas how I can achieve this use case with Mockito?
1) what you are trying to do is calling a test case from from a test case.
2) Mocking is used mainly for testing the endpoint, may be for controllers.So if your save functions needs to called again or you have to reuse the code for other test case, you should do that, it has no problem.
But what you are saying is totally against the programming paradigms for mock test cases.
In my opinion needing a mocking like that should be avoided, but if you insist you can leverage the doAnswer() method for detailed mock handling.
Basically, you use two Answer instances. One that sets a flag when the method is called with 2, the other one resetting the flag.
Another answer reacts to that flag and throws an exception if needed.
private boolean throwExceptionNext;
#Test
public void test() {
Service mock = Mockito.mock(Service.class);
Mockito.doAnswer((__) -> {
throwExceptionNext = false;
return new Object();
}).when(mock).get(Mockito.anyInt());
Mockito.doAnswer((__) -> {
throwExceptionNext = true;
return new Object();
}).when(mock).get(2);
Mockito.doAnswer((__) -> {
if (throwExceptionNext)
throw new RuntimeException();
return null;
}).when(mock).save();
mock.get(3);
mock.save();
mock.get(2);
try {
mock.save();
Assert.fail();
} catch (RuntimeException e) {
}
mock.get(3);
mock.save();
}

Unit Testing Java Code - Mocking a non-static method of a different class

public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
Here I want to test the method "doSecond()" of class "First". For the same, I want to mock the method "doJob" of class "Second".
I know that I can create a mocked instance of class "Second" using the code below.
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
But I cannot relate this mocked instance with class "First" as of the current code.
Without refactoring the source code, is there any way by which i can achieve the requirement.
Please help.
Take a look at powermock's ability to intercept calls to new and return mocks instead
https://code.google.com/p/powermock/wiki/MockConstructor
This doesn't require changing any sourcecode.
here's the test code where we actually return a mock when First.doSecond() calls new Second()
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class TestFirst {
#Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
It's tricky to mock an instance that you create inside of a method, but it's possible.
Using PowerMock, you can accomplish this with the PowerMock.expectNew() method:
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class StackOverflowTest {
#Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
Effectively, PowerMock is proxying the creation of the new object and substituting whatever value we want when we invoke doSecond().
So, it's possible. However, this is a terrible practice to get into.
One typically wants to mock objects if they involve an outside concern, such as another layer (i.e. database, validation), or if the desired output is coming from other objects that are injected but are safe enough to consider tested.
If your method is capable of getting or retrieving data from a non-injectable source, you should not want to mock that out.
Considering that your method is simple and straightforward, you should really not need to do any mocks here at all. But if you felt that you were forced to, you could do one of a few things:
Create a factory for the creation of Second, and mock the results of the returning factory object with Mockito.
Pass in an instance of Second to that method, and use Mockito as the mock instance.
Declare it as a field (i.e. injected dependency), and use Mockito.
For completeness, here is how the test can be written with the JMockit mocking API, without any refactoring of the original code under test:
public class ExampleTest
{
#Test
public void firstShouldCallSecond(#Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}

Categories

Resources