Getting null as result of a mocked method call in Android JUnit - java

I am trying to mock a function that is being called within another function. But I am getting end result as null. I tried to mock the second function that is being used in actual function.
Here is my code:
#RunWith(MockitoJUnitRunner.class)
public class LoadJsonData_Test {
#Mock
LoadJsonData loadJsonData;
#Test
public void getChartTypeJS_test() {
String jsonStr = "";
try {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("chartInfo.json");
int size = is.available();
byte[] buffer = new byte[size];
if (is.read(buffer) > 0)
jsonStr = new String(buffer, "UTF-8");
is.close();
} catch (IOException ex) {
ex.printStackTrace();
}
when(loadJsonData.getJsonData()).thenReturn(jsonStr);
System.out.println(loadJsonData.getJsonData()); //Printing the data I wanted
assertEquals(loadJsonData.getChartTypeJS(),
"javascript:setChartSeriesType(%d);"); // loadJsonData.getChartTypeJS() returns null
}
Code I am trying to test:
public String getJsonData() {
try {
InputStream is = mContext.getAssets().open("chartInfo.json");
int size = is.available();
byte[] buffer = new byte[size];
if (is.read(buffer) > 0)
jsonString = new String(buffer, "UTF-8");
is.close();
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return jsonString;
}
public String getChartTypeJS() {
jsonString = getJsonData();
try {
JSONObject jsonObject = new JSONObject(jsonString);
JSONObject javascriptEvent_JsonObject = jsonObject.getJSONObject("javascript_events");
return javascriptEvent_JsonObject.getString("chartType");
} catch (JSONException e) {
e.printStackTrace();
}
return "";
}
What is it I am doing wrong?
Thanks

You are mocking LoadJsonData and then invoking two methods on it:
getJsonData()
getChartTypeJS()
You create an expectation on the response from getJsonData() here:
when(loadJsonData.getJsonData()).thenReturn(jsonStr);
But since the mock has no expectation for a response from getChartTypeJS() this invocation returns null: loadJsonData.getChartTypeJS().
It looks like LoadJsonData should be a Spy not a Mock since that would allow you to mock getJsonData() but invoke the actual implementation of getChartTypeJS().
For example:
#Spy
LoadJsonData loadJsonData;
// this wil tell Mockito to return jsonStr when getJsonData() is invoked on the spy
doReturn(jsonStr).when(loadJsonData.getJsonData());
// this will invoke the actual implementation
assertEquals(loadJsonData.getChartTypeJS(), "javascript:setChartSeriesType(%d);");
More details on spying (aka partial mocks) here.

Related

How to retrieve object from key value database into Map, then convert back to object in Java

I am storing an object as a value in LevelDB. Both key and value must be in bytes for LevelDB.
I am receiving an object via a socket and casting it to MyObject:
MyObject myObject = (MyObject) (objectInput.readObject());
Then I am serialising my object when storing the value in LevelDB:
myLevelDb().put(bytes((publicKey)), Serializer.serialize(myObject));
The serializer code is as follows:
public static byte[] serialize(Object object) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(object);
out.flush();
byte[] yourBytes = bos.toByteArray();
return yourBytes;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
Then I am trying to iterate through the LevelDB and store each object into a Map. Here is where I am trying to deserialize the bytes back into MyObject and save them to Map:
private void iterateBytes() {
DBIterator iterator = myLevelDb().iterator();
while (iterator.hasNext()) {
Map.Entry<byte[], byte[]> next = iterator.next();
String keyString = new String(next.getKey());
MyObject myObject = (MyObject) Serializer.deserialize(next.getValue());
Map<String, MyObject> myMap = new HashMap<>();
myMap().put(keyString, myObject);
}
}
However, Java will not let me cast the deserialized bytes back to MyObject after it has been deserialized using the following code:
public static Object deserialize(byte[] bytes) {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
Object o = in.readObject();
return o;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
I don't understand why I cannot convert the object back from a byte[] when I have followed the exact same method of serializing and deserializing. MyObject implements Serializable and the SUID is correct, as it works on API calls between devices. I just cannot add it to a Map as the original object, nor will Java let me cast it.
This is the line where an error is thrown, no matter where I try to cast it back to myObject:
MyObject myObject = (MyObject) Serializer.deserialize(next.getValue());
Error:
class java.lang.String cannot be cast to class myPackage.MyObject (java.lang.String is in module java.base of loader 'bootstrap';
This was solved by casting the generic Object object to MyObject (user defined class object) at serialization and also casting it at deserialization.
Here is the code at serialization:
public static byte[] serialize(MyObject myObject) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(myObject);
out.flush();
byte[] yourBytes = bos.toByteArray();
return yourBytes;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
And here is the code for deserializaion.
public static MyObject deserializeNodeClient(byte[] bytes) {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
MyObject myObject = (MyObject) in.readObject();
return myObject;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
} return null;
}
So although the original OP code works fine is some cases, the original object cannot be derived by using a generic Object object serialization, then casting the output.

Extract value from Json using Gson

I am trying to extract values from JSON from the URL provided below using GSON java library:
http://api.wunderground.com/api/b28d047ca410515a/forecast/q/-33.912,151.013.json
I have successfully used the code provided below to extract data from URL below:
http://api.wunderground.com/api/b28d047ca410515a/conditions/q/-33.912,151.013.json
Code:
String url = "http://api.wunderground.com/api/b28d047ca410515a/conditions/q/-33.912,151.013.json";
String url2 = "http://api.wunderground.com/api/b28d047ca410515a/forecast/q/-33.912,151.013.json";
InputStream is = null;
try {
is = new URL(url).openStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JsonElement je = new JsonParser().parse(jsonText);
System.out.println("Current Temperature:" + getAtPath(je, "current_observation/temp_c").getAsString() );
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
However I am getting exception trying to extract from url2 as per code below , it seems to be a more complicated json to get values from, any help please?
// below code not working
weather_icon_url = getAtPath(je, "current_observation/icon_url").getAsString();
is = new URL(url2).openStream();
BufferedReader rd2 = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText2 = readAll(rd2);
JsonElement je2 = new JsonParser().parse(jsonText2);
System.out.println("max Temperature:" + getAtPath(je2, "forecast/simpleforecast/forecastday/high/celsius").getAsString() );
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
getAtPath code:
private static JsonElement getAtPath(JsonElement e, String path) {
JsonElement current = e;
String ss[] = path.split("/");
for (int i = 0; i < ss.length; i++) {
current = current.getAsJsonObject().get(ss[i]);
}
return current;
}
The problem you are facing is because there is an issue with the getAtPath implementation.
[{"date":{"epoch":"1459152000"... represents a JSONArray which the method is trying to access as JSONObject. Hence the IllegalStateException.
JsonObject com.google.gson.JsonElement.getAsJsonObject()
convenience method to get this element as a JsonObject. If the element
is of some other type, a IllegalStateException will result. Hence it
is best to use this method after ensuring that this element is of the
desired type by calling isJsonObject() first.
You can update and use something like below, as of now it returns only the first element.
private static JsonElement getAtPath(JsonElement e, String path) {
JsonElement current = e;
String ss[] = path.split("/");
for (int i = 0; i < ss.length; i++) {
if(current instanceof JsonObject){
current = current.getAsJsonObject().get(ss[i]);
} else if(current instanceof JsonArray){
JsonElement jsonElement = current.getAsJsonArray().get(0);
current = jsonElement.getAsJsonObject().get(ss[i]);
}
}
return current;
}
This should work:
System.out.println("max Temperature:" + getAtPath(je2, "forecast/simpleforecast/forecastday/high/celsius").getAsString() );

How to pass string in android without error- A resource was acquired at attached stack trace but never released-

I try to fetch stringBuilder object to the my main activity. I check my json file or parsing codes they works well. However when I try to fetch stringbuilder it gave an error:
A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
code for Server.java is as below
`
public class Server extends Activity {
static StringBuilder stringBuilder = new StringBuilder();
public Server(){
try {
JSONObject obj = new JSONObject(loadJSONFromAsset());
JSONArray project = obj.getJSONArray("project");
for (int i = 0; i < project.length(); i++) {
JSONObject ss = project.getJSONObject(i);
stringBuilder.append(ss.getString("title") + "\n");
JSONArray post = ss.getJSONArray("posts");
for(int j = 0; j < post.length();j++){
JSONObject posts = post.getJSONObject(j);
stringBuilder.append(posts.getString("id") +"\n");
JSONArray tag = posts.getJSONArray("tags");
for(int k = 0; k < tag.length();k++){
stringBuilder.append(tag.getString(k) +"\n");
}
}
}
}
catch (JSONException e) {
stringBuilder.append("error");
e.printStackTrace();
}
}
public String getString(){
return stringBuilder.toString();
}
public String loadJSONFromAsset() {
String json = null;
try {
InputStream is = getAssets().open("cat.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}}
and here is my MainActivity.java
public class MainActivity extends Activity {
TextView jsonDataTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jsonDataTextView = (TextView) findViewById(R.id.textView);
Server s = new Server();
jsonDataTextView.setText(s.stringBuilder.toString());} }
Is there any solution?
The InputStream may not be closed in the try block of your loadJSONFromAsset method, and it should.
public String loadJSONFromAsset() {
String json = null;
InputStream is = null;
try {
is = getAssets().open("cat.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
json = new String(buffer, "UTF-8");
}
catch (IOException ex) {
ex.printStackTrace();
}
finally {
if (is != null) {
try {
is.close();
}
catch (IOException ex) {
// Do you want to handle this exception?
}
}
}
return json;
}
Note: Something bothers me in your Server constructor, in the catch block you try to append "error" to your StringBuilder. Do you know that here, the StringBuilder may not be empty. Indeed in the try block, one (or more) attempt(s) to append some string to it may work before something goes wrong at some point.
Note 2: Server as a non Activity
public class Server {
private Context mContext;
public Server(Context context) {
mContext = context;
...
}
...
public String loadJSONFromAsset() {
...
mContext.getAssets().open("cat.json");
}
}
then in your MainActivity
Server s = new Server(this);

How to put multiple elements into byte[] in java

How can I put multiple elements into byte[]? I have the following 3 elements: 1) String data , 2) String status and 3) HashMap<String,String> headers, which need to be passed to setContent(byte[] data) as byte arrays. The following is the code in which I would like to use the previous 3 parameters as input for statusResult.setContent():
public void onSuccess(ClientResponse clientResponse){
String data=clientResponse.getMessage();
String status=String.valueOf(clientResponse.getStatus());
HashMap<String,String> headers=clientResponse.getHeaders();
// Now StatusResult is a class where we need to pass all this data,having only getters and
// setters for Content,so here in the next line i need to pass data,status and headers as
// a byte[] to setContent.
statusResult.setContent(byte[]);
}
Can somebody help me to resolve this out?
This is serialization in a crude way. I would suggest the following:
Create a class encapsulating the three elements.
Make sure that class implements serializable interface.
Use the following code [taken from this post] to create a byte array as you wished, and read the object back from byte array (which, although you have not specified as requirement, but it needs mention for the sake of completeness)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
try {
//Assuming that bos is the object to be seriaized
out = new ObjectOutputStream(bos);
out.writeObject(yourObject);
byte[] yourBytes = bos.toByteArray();
...
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ex) {
// ignore close exception
}
try {
bos.close();
} catch (IOException ex) {
// ignore close exception
}
}
//Create object from bytes:
ByteArrayInputStream bis = new ByteArrayInputStream(yourBytes);
ObjectInput in = null;
try {
in = new ObjectInputStream(bis);
Object o = in.readObject();
...
} finally {
try {
bis.close();
} catch (IOException ex) {
// ignore close exception
}
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
// ignore close exception
}
}

Serialise/Deserialise List<String>

I was to save an arraylist of strings into 1 column in the local database. I am having some problems doing this. Can somebody tell me where I am going wrong...
private String serializeArray(List<String> array) {
try {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bytesOut);
oos.writeObject(array);
oos.flush();
oos.close();
return Base64.encodeToString(bytesOut.toByteArray(), Base64.NO_WRAP);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private ArrayList<String> deserializeArray(String string) {
Log.d("USERDAO", string);
try {
ByteArrayInputStream bytesIn = new ByteArrayInputStream(Base64.decode(string, Base64.NO_WRAP));
ObjectInputStream ois = new ObjectInputStream(bytesIn);
return (ArrayList<String>) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I am getting a null pointer exception when returning the Arraylist on deserialise array. The serialiseArray method does return a string however I am not sure if it is correct.
When I run this in eclipse I get java.lang.ClassCastException at this line:
return (ArrayList<String>) ois.readObject();
the readObject() method is trying to return an Arrays$ArrayList (whatever that is) and your cast is causing it to break. If you change the cast and the return type of your deserialise to be List you'll find it all works.

Categories

Resources