How do I test this function using mockito and junit? - java

I'm new to mockito and junit5. I'm trying to test the below function:
public boolean checkFunction(String element) {
CloseableHttpClient client = HttpClients.createDefault();
String uri = "any url im hitting";
HttpPost httpPost = new HttpPost(uri);
String json = element;
StringEntity entity;
try {
entity = new StringEntity(json);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Authorization", "any token");
CloseableHttpResponse response = client.execute(httpPost);
String responseBody = EntityUtils.toString(response.getEntity());
client.close();
if (responseBody.contains("any string i wanna check"))
return true;
} catch (Exception e) {
return false;
}
return false;
}
I tried the below code but I'm unable to get entire code coverage. Also I don't think this is the right approach.
#Test
public void testCheckFunction() throws Exception {
when(mockClass.checkFunction(Mockito.anyString())).thenReturn(false);
assertEquals(false, mockclass.checkFunction("dummy"));
}
Can anyone help me with this?
Thanks!

First you have to refactor your code for better testability:
public class Checker {
private final CloseableHttpClient client;
public Checker(CloseableHttpClient client) {
this.client = client;
}
public boolean checkFunction(String element) {
String uri = "http://example.com";
HttpPost httpPost = new HttpPost(uri);
String json = element;
StringEntity entity;
try {
entity = new StringEntity(json);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Authorization", "any token");
CloseableHttpResponse response = client.execute(httpPost);
String responseBody = EntityUtils.toString(response.getEntity());
client.close();
if (responseBody.contains("any string i wanna check"))
return true;
} catch (Exception e) {
return false;
}
return false;
}
}
Note that the dependency (i.e. the thing that has to be mocked in tests) is now injected via the constructor. This way it can easily be replaced by a mock when unit testing this class:
class CheckerTest {
private final CloseableHttpClient clientMock = Mockito.mock(CloseableHttpClient.class);
private final Checker checker = new Checker(clientMock);
#Test
public void testCheckFunction() throws Exception {
when(clientMock.execute(any(HttpPost.class))).thenThrow(new RuntimeException("Oops!"));
assertFalse(checker.checkFunction("dummy"));
}
}

Related

try with resources in a method used by another one

I have the following java code with try with resources:
public static CloseableHttpResponse getHttpResponse()
{
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
try (CloseableHttpResponse response = client.execute(request)) {
return response;
}
}
}
in another method will use the response returned by getHttpResponse:
public void test() {
CloseableHttpResponse response = getHttpResponse();
if (response) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
}
}
Looks like after CloseableHttpResponse response = getHttpResponse();, the client and response already closed, and I can not put this two methods into one, are there any ways that still use the try with resources in another method?
The best approach is the Execute Around idiom. Instead of getHttpResponse returning a CloseableHttpResponse pass in a lambda (typically) to be executed. The resource can then be closed in a try-with-resource statement cleanly.
/*** NICE ***/
// Function instead of Consumer would allow the method to return a value.
private void httpResponse(
Consumer<CloseableHttpResponse> op
) /* throws IOException */ {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
try (CloseableHttpResponse response = client.execute(request)) {
if (response != null) { // Really?
op.accept(response);
}
}
}
}
Used as:
httpResponse(response -> {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
});
The hacky alternative is to include a try statement within getHttpResponse that only closed in error conditions.
/*** HACKY ***/
private CloseableHttpResponse httpResponse() /* throws IOException */ {
boolean success = false;
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
CloseableHttpResponse response = client.execute(request);
try {
success = true;
return response;
} finally {
if (!success) {
response.close();
}
}
} finally {
if (!success) {
client.close();
}
}
}
client will be closed as soon as the program leaves the scope of the try-with-resources. Can you try building the try with resources around the getHttpResponse method? For example:
public static CloseableHttpResponse getHttpResponse() {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
CloseableHttpResponse response = client.execute(request)
return response;
}
}
And then you can rewrite your test method() like this:
public void test() {
try(CloseableHttpResponse response = getHttpResponse()) {
if (response) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
}
}
}

org.json.JSONException: A JSONObject text must begin with '{' at character 1

I tried searching for this error. There are many results on google for this search but nothing proved useful to me.
This is my web service method
#GET
#Path("/values")
public String test() {
return "{\"x\":5,\"y\":6}";
}
This is my client code
public class Check {
public static void main(String[] args){
String url = "http://localhost:8181/math/webapi/values";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(request);
String value = response.toString();
JSONObject json = new JSONObject(value);
int i = json.getInt("x");
System.out.println(i);
}catch (Exception e) {
e.printStackTrace();
}
}
The above code is a starter code and it is for learning how to use it. If this is solved, I have to apply the knowledge in another application. The client side code, I want to use the logic in android.
EDIT
public class Check {
public static void main(String[] args){
String url = "http://localhost:8181/math/webapi/values";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(request);
InputStream value = response.getEntity().getContent();
BufferedReader br = new BufferedReader(new InputStreamReader(value));
String jsonValue = br.readLine();
JSONObject json = new JSONObject(jsonValue);
int i = json.getInt("x");
System.out.println(i);
}catch (Exception e) {
e.printStackTrace();
}
}
Fairly certain response.toString doesn't do what you think it does, as it's not listed in the documentation.
I believe you need to use response.getEntity, and then entity.getContent, which gives you an InputStream to read the content from. Then pass that stream into your parser.
Try this code. Use IOUtils as mentioned. it will work.
public class Check {
public static void main(String[] args){
String url = "http://localhost:8181/math/webapi/values";
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(request);
InputStream value = response.getEntity().getContent();
String jsonValue = IOUtils.toString(value);
JSONObject json = new JSONObject(jsonValue);
int i = json.getInt("x");
System.out.println(i);
}catch (Exception e) {
e.printStackTrace();
}
}

grails receive file via MultipartEntity

I use this httpclient to post a image to my grails as follows. How do I receive the file in grails?
public static String webPost(String method, File data, Context c) throws Exception {
String json = "";
if (isOnline(c) == true) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
HttpPost httppost ;
try {
httppost = new HttpPost(method);
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("image", new FileBody(data));
httppost.setEntity(entity);
response = httpclient.execute(httppost);
if (response != null) {
HttpEntity r_entity = response.getEntity();
json = EntityUtils.toString(r_entity);
Log.i("ja", json);
}
} catch (Exception e) {
throw new RuntimeException(e.getLocalizedMessage());
} finally {
httpclient = null;
response = null;
httpclient = null;
}
} else {
throw new RuntimeException("No internet connection");
}
return json;
}
My grails:
def image = request.getFile('image')
image.transferTo(new File('c:/p.png') )
Error:
groovy.lang.MissingMethodException: No signature of method: org.apache.catalina.core.ApplicationHttpRequest.getFile() is applicable for argument types: (java.lang.String) values: [image]
Possible solutions: getXML(), getAt(java.lang.String), getAt(java.lang.String), getLocale(), getInfo(), recycle()
at mclient.TestController$_closure1.doCall(TestController.groovy:10)
at mclient.TestController$_closure1.doCall(TestController.groovy)
at java.lang.Thread.run(Thread.java:662)

Android: send post that has no response

In my app, I need to send all sorts of POST requests to a server. some of those requests have responses and others don't.
this is the code I'm using to send the requests:
private static final String TAG = "Server";
private static final String PATH = "http://10.0.0.2:8001/data_connection";
private static HttpResponse response = null;
private static StringEntity se = null;
private static HttpClient client;
private static HttpPost post = null;
public static String actionKey = null;
public static JSONObject sendRequest(JSONObject req) {
try {
client = new DefaultHttpClient();
actionKey = req.getString("actionKey");
se = new StringEntity(req.toString());
se.setContentEncoding(new BasicHeader(HTTP.CONTENT_ENCODING, "application/json"));
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post = new HttpPost(PATH);
post.setEntity(se);
Log.d(TAG, "http request is being sent");
response = client.execute(post);
Log.d(TAG, "http request was sent");
if (response != null) {
InputStream in = response.getEntity().getContent();
String a = convertFromInputStream(in);
in.close();
return new JSONObject(a);
}
} catch (UnsupportedEncodingException e) {
Log.d(TAG, "encoding request to String entity faild!");
e.printStackTrace();
} catch (ClientProtocolException e) {
Log.d(TAG, "executing the http POST didn't work");
e.printStackTrace();
} catch (IOException e) {
Log.d(TAG, "executing the http POST didn't work");
e.printStackTrace();
} catch (JSONException e) {
Log.d(TAG, "no ActionKey");
e.printStackTrace();
}
return null;
}
private static String convertFromInputStream(InputStream in)
throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return (sb.toString());
}
This is the code for the AsyncTask class that sends the request:
class ServerRequest extends AsyncTask<JSONObject, Void, JSONObject> {
#Override
protected JSONObject doInBackground(JSONObject... params) {
JSONObject req = params[0];
JSONObject response = Server.sendRequest(req);
return response;
}
#Override
protected void onPostExecute(JSONObject result) {
// HANDLE RESULT
super.onPostExecute(result);
}
}
my problem starts when the server doesn't return a response. the AsyncTask thread stays open even after the work is done because the HTTPClient never closes the connection.
Is there a way to not wait for a response? this is something that will definitely add a lot of overhead to the server since all the Android apps trying to connect to it will keep the connection alive, and will probably cause many problems on the app itself.
Basically, what I'm looking for is a method that will allow me to send to POST message and kill the connection right after the sending of the request since there is no response coming my way.
Just, Set ConnectionTimeOut with HttpClient Object, (Code is for your understanding in your case it may be different)
int TIMEOUT_MILLISEC = 30000;
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT_MILLISEC);
HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT_MILLISEC);
HttpClient httpclient = new DefaultHttpClient(httpParams);
HttpPost httppost = new HttpPost(url);
httppost.addHeader("Content-Type", "application/json");
Now, It will terminate the Connection after TimeoOut you defined. But be sure this will throw TimeOutException so You have to handle this exception in your HttpRequest.. (Use Try -catch)
EDIT: Or you can use HttpRequestExecutor class.
From class HttpRequestExecutor of package org.apache.http.protocol
protected boolean canResponseHaveBody (HttpRequest request, HttpResponse response)
Decide whether a response comes with an entity. The implementation in this class is based on RFC 2616. Unknown methods and response codes are supposed to indicate responses with an entity.
Derived executors can override this method to handle methods and response codes not specified in RFC 2616.

Making a POST call to Google Translate with Jersey returns HTTP 404

I'm trying to write a POST call to Google Translate with Jersey 1.5. This is my code:
package main;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import javax.ws.rs.core.MultivaluedMap;
public class Main {
private static String GOOGLE_TRANSLATE_URL = "https://www.googleapis.com/language/translate/v2";
private static String translateString(String sourceString, String sourceLanguage, String targetLanguage) {
String response;
Client c = Client.create();
WebResource wr = c.resource(GOOGLE_TRANSLATE_URL);
MultivaluedMap<String, String> params = new MultivaluedMapImpl();
params.add("q", sourceString);
params.add("source", sourceLanguage);
params.add("target", targetLanguage);
params.add("key", "xxxx");
wr.header("X-HTTP-Method-Override", "GET");
response = wr.post(String.class, params);
return response;
}
public static void main(String[] args) {
System.out.println(translateString("Hello", "en", "sv"));
}
}
When I run this, all I get back is this: com.sun.jersey.api.client.UniformInterfaceException: POST https://www.googleapis.com/language/translate/v2 returned a response status of 404.
I've managed to accomplish this with a simple cURL command like so:
curl --header "X-HTTP-Method-Override: GET" -d key=xxxx -d q=Hello -d source=en -d target=sv https://www.googleapis.com/language/translate/v2
Thanks in advance!
I suspect that POST with zero Content-Length is not something a normal HTTP server will accept. The RFC does not define this case, but the main assumption of POST is that you're sending a message body.
Looking at the Google API, they mention the following
You can also use POST to invoke the API if you want to send more data in a single request. The q parameter in the POST body must be less than 5K characters. To use POST, you must use the X-HTTP-Method-Override header to tell the Translate API to treat the request as a GET (use X-HTTP-Method-Override: GET).
This means that instead of adding q, source and target parameters in the URL, you need to do so in the POST body. I'm not familiar with the Jersey API, from a brief look you just need to add params as an explicit second parameter to the .post call, remove the queryParams() call, and set the Content-Length properly.
I think the best and correct way is this
private static final String gurl = "www.googleapis.com";
private static final String gpath = "/language/translate/v2/detect";
public String detectLangGooglePost(String text) throws SystemException {
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("key", key));
URI uri;
try {
uri = URIUtils.createURI("https", gurl, -1, gpath, URLEncodedUtils.format(qparams, "UTF-8"), null);
} catch (URISyntaxException e) {
throw new SystemException("Possibly invalid URI parameters", e);
}
HttpResponse response = getPostResponse(uri, text);
StringBuilder builder = getBuilder(response);
String language = getLanguage(builder);
return language;
}
private HttpResponse getPostResponse(URI uri, String text) throws SystemException {
List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("q", text));
HttpResponse response;
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader("X-HTTP-Method-Override", "GET");
try {
httpPost.setEntity(new UrlEncodedFormEntity(qparams));
response = httpclient.execute(httpPost);
} catch (Exception e) {
throw new SystemException("Problem when executing Google get request", e);
}
int sc = response.getStatusLine().getStatusCode();
if (sc != HttpStatus.SC_OK)
throw new SystemException("google status code : " + sc);
return response;
}
private StringBuilder getBuilder(HttpResponse response) throws SystemException {
HttpEntity entity = response.getEntity();
if (entity == null)
throw new SystemException("response entity null");
StringBuilder builder = new StringBuilder();
BufferedReader in = null;
String str;
try {
in = new BufferedReader(new InputStreamReader(entity.getContent()));
while ((str = in.readLine()) != null)
builder.append(str);
} catch (IOException e) {
throw new SystemException("Reading input stream of http google response entity problem", e);
} finally {
IOUtils.closeQuietly(in);
}
if (builder.length() == 0)
throw new SystemException("content stream of response entity empty has zero length");
return builder;
}
private String getLanguage(StringBuilder builder) throws SystemException {
JSONObject data = null;
JSONArray detections = null;
String language = null;
JSONObject object = (JSONObject) JSONValue.parse(builder.toString());
if (object == null)
throw new SystemException("JSON parsing builder object returned null");
if (object.containsKey("data") == false)
throw new SystemException("JSONObject doesn't contain data key");
data = (JSONObject) object.get("data");
detections = (JSONArray) data.get("detections");
if (detections == null)
throw new SystemException("JSON detections is null");
JSONObject body = (JSONObject) ((JSONArray) detections.get(0)).get(0);
if (body == null)
throw new SystemException("detections body is null");
if (body.containsKey("language") == false)
throw new SystemException("language key is null");
language = (String) body.get("language");
if (language == null || language.equals(unknown))
throw new SystemException("Google lang detection - resulting language : " + language);
return language;
}
I was able to send very long text like this!
Client:
MultivaluedMap<String,String> formData = new MultivaluedMapImpl();
formData.add("text", text);
WebResource resource = Client.create().resource(getBaseURI()).path("text2rdf");
return resource.type("application/x-www-form-urlencoded").post(String.class, formData);
Server:
#POST
#Produces("text/whatever")
public String textToRdf (
#FormParam("text") String text) {...
I switched to Apache HttpClient 4.x and solved it like this instead:
public class Main {
private static String GOOGLE_TRANSLATE_URL = "https://www.googleapis.com/language/translate/v2";
private static String GOOGLE_API_KEY = "xxxx";
private static String translateString(String sourceString, String sourceLanguage, String targetLanguage) {
String response = null;
// prepare call
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(GOOGLE_TRANSLATE_URL+"?q="+sourceString+"&source="+sourceLanguage+"&target="+targetLanguage+"&key="+GOOGLE_API_KEY);
post.setHeader("X-HTTP-Method-Override", "GET");
try {
// make the call
ResponseHandler<String> responseHandler = new BasicResponseHandler();
response = client.execute(post, responseHandler);
} catch (IOException e) {
// todo: proper error handling
}
return response;
}
public static void main(String[] args) {
System.out.println(translateString("hello", "en", "sv"));
}
}
Don't really know why this works better than Jersey, but it works. Thanks for trying to help!

Categories