Reputation: 1
I have a service class which transforms JSON from one pattern to other using DynamoDB. This class have various methods to manipulate JSON fields, as shown below. I have to write JUnit tests on this code using Mockito. The convertToProviderJson method transform one JSON which is coming from 3rd party, to a predefined template and following methods are manipulating details present on the transformed JSON.
I am new to JUnit & Mockito, how shall I proceed?
```
@Service
public class ServiceClass {
public String convertToProviderJson(String consumerString, String providerTemplateJson)
throws JsonProcessingException {
//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();
//convert json file to map
String currentFieldName = "";
String currentTemplateKey = "";
boolean templateMatchError = false;
Map<?, ?> providerMap;
Map<String, Object> providerOutputMap = new LinkedHashMap<>();
System.out.println("Provider JSON");
if(!UtilityClass.isJSONValid(consumerString)) {
throw new MalformedJsonException("Incorrect Consumer Input JSON.");
}
if(!UtilityClass.isJSONValid(providerTemplateJson)) {
throw new MalformedJsonException("Incorrect Provider Template JSON.");
}
try {
JSONObject consumerJson = new JSONObject(consumerString);
providerMap = objectMapper.readValue(providerTemplateJson, Map.class);
//iterate over Provider Template map.
for (Map.Entry<?, ?> entry : providerMap.entrySet()) {
String key = (String) entry.getKey();
currentTemplateKey = key;
String value = (String) entry.getValue();
Pattern p = Pattern.compile(TransformationConstants.TEMPLATE_FUNCTION_REGEX);
Matcher matcher = p.matcher((CharSequence) entry.getValue());
if (matcher.matches()) {
String[] splitString = value.split(LEFT_ROUND_BRACKET);
String functionName = splitString[0];
String fieldName = splitString[1].split(RIGHT_ROUND_BRACKET)[0];
currentFieldName = fieldName;
Object fieldValue = invokeFunction(consumerJson, functionName, fieldName);
providerOutputMap.put(key, fieldValue);
} else {
templateMatchError = true;
break;
}
}
} catch(JsonEOFException e) {
throw new MalformedJsonException("Incorrect Provider Template JSON.");
} catch (Exception e) {
throw new MalformedJsonException("Field '" + currentFieldName + "' missing in input json.");
}
if(templateMatchError) {
throw new MalformedJsonException("Value for Field '" + currentTemplateKey
+ "' in template JSON is not in correct format.");
}
String outputJson = objectMapper.writeValueAsString(providerOutputMap);
System.out.println("Provider JSON: " + outputJson);
return outputJson;
}
private Object invokeFunction(JSONObject consumerJson, String functionName, String fieldName)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
TransformationService obj = new TransformationService();
Method method;
method = obj.getClass().getMethod(functionName, JSONObject.class, String.class);
return method.invoke(obj, consumerJson, fieldName);
}
public Object getField(JSONObject jsonObject, String fieldName) throws JSONException {
if(jsonObject.has(fieldName)) {
return jsonObject.get(fieldName);
}
throw new MalformedJsonException("Field '" + fieldName + "' missing in input json.");
}
}
I have tried to write Unit test on getField() method after going through some articles. Here's my code, I know its wrong, how shall I proceed?
@Test
public void hasFieldTest() {
JSONObject obj = new JSONObject();
obj.put("id", "1");
obj.put("name", "divyanka");
when(((Object) transformationMock.getField(jsonObjmock, "name")).thenReturn(objectMock);
JSONAssert.assertEquals("{id:1}", obj, 'strict':false);
}
Upvotes: 0
Views: 9156
Reputation: 13289
To test (the getField
method of) ServiceClass
, i would approach like:
import static org.junit.jupiter.api.Assertions.assertThrows;
// ...
class ServiceClassTest {
//Object/Class under test:
private ServiceClass testee = new ServiceClass(); // create new or "obtain somewhere" (like @Autowired in Spring testing...)
//... test all methods, lines:
@Test
public void testGetFieldOK() {
// prepare "good" object:
JSONObject obj = new JSONObject();
obj.put("foo", "bar");
// TEST/invoke (!):
Object result = testee.getField(obj, "foo");
// assert (with your assertion framework/style):
// result is not null AND result == "bar"
// done!
}
@Test
public void testGetFieldException() {
// prepare "bad" object:
JSONObject obj = new JSONObject();
// Test/Expect exception -> https://stackoverflow.com/a/40268447/592355 ->:
MalformedJsonException thrown = assertThrows(
MalformedJsonException.class,
() -> testee.getField(obj, "foo"),
"Expected getField(obj, \"foo\") to throw, but it didn't"
);
//assert on exception (message):
assertTrue(thrown.getMessage().contains("Field 'foo' missing in input json."));
}
//create more tests like that... (-> coverage),
//.. WHEN real parameters, associated objects and class (invocations) are not applicable, mock them!
}
Thx to: https://stackoverflow.com/a/40268447/592355
And to summarize the main topics:
So in your code: ObjectMapper
and TransformationService
look like possible mocking candidates, but it is not worth, since they are created locally (in the methods to test).
UtilityClass
could also be (power) mocked, but is it worth!?? :-)
In case UtilityClass
would be an (external) productive (chargeable) API, you might want to mock it.
Upvotes: 1