I have a service I am mocking like this:
#ExtendWith(MockitoExtension.class)
class MyServiceTest {
#InjectMocks
MyService myService;
#Test
void testSendRec() {
myService.sendDocRec(.. pass params..);
}
}
the service:
#Service
public class MyService {
String sendDocRec( params ) {
// builds request
HttpUriRequestBase request = getRequest( params );
String response = doRequest(request);
}
public String doRequest(ClassicHttpRequest request) {
String result = null;
try (CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(this.connectionManager)
.setConnectionManagerShared(true)
.setDefaultRequestConfig(this.requestConfig)
.build()) {
final HttpClientContext clientContext = HttpClientContext.create();
try (CloseableHttpResponse response = httpclient.execute(request, clientContext)) {
result = EntityUtils.toString(response.getEntity());
}
} catch (URISyntaxException e) {
log.error("Invalid URI {}", e);
} catch (IOException e) {
log.error("Failed to make HTTP Request {}", e);
} catch (ParseException e) {
log.error("Failed parsing response body {}", e);
}
return result;
}
}
I need to be able to mock the "CloseableHttpResponse response = httpclient.execute(request, clientContext)", such that the "response" object is something I create ahead of time. I am hoping some mocking when/then constructs would work for this? I would grateful for ideas on how to do this. Thanks!
You can't do it using the current code structure. httpclient object is getting created within the method under test. So it can't be mocked.
You need to delegate httpclient object creation to another method with belongs to a different class (something similar to HttpClientFactory class). That HttpClientFactory class should only be responsible for creating httpClient instances. If you need you can write separate unit test case for the class.
#Inject
private HttpClientFactory httpClientFactory;
public String doRequest(ClassicHttpRequest request) {
String result = null;
try (CloseableHttpClient httpclient = httpClientFactory.getInstance()) {
final HttpClientContext clientContext = HttpClientContext.create();
try (CloseableHttpResponse response = httpclient.execute(request, clientContext)) {
result = EntityUtils.toString(response.getEntity());
}
} catch (URISyntaxException e) {
log.error("Invalid URI {}", e);
} catch (IOException e) {
log.error("Failed to make HTTP Request {}", e);
} catch (ParseException e) {
log.error("Failed parsing response body {}", e);
}
return result;
}
Now you can mock response like below:
#Mock
private HttpClientFactory httpClientFactory;
public String testDoRequest(ClassicHttpRequest request) {
....
CloseableHttpClient mockedClient = mock(CloseableHttpClient.class);
CloseableHttpResponse mockedResponse = mock(CloseableHttpResponse.class);
when(httpClientFactory.getInstance()).thenReturn(mockedClient);
when(mockedClient.execute(eq(request), any(clientContext))).thenReturn(mockedResponse);
....}
Related
public String sendAPICall(String portalApiUrl, String reviewAppsAuthKey) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(portalApiUrl + CHECK_ORG_ATT_EXP))
.setHeader(AUTH_REVIEW_API_KEY, reviewAppsAuthKey)
.setHeader(CONTENT_TYPE, APPLICATION_JSON)
.GET()
.build();
HttpClient httpClient = HttpClient.newHttpClient();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == HttpStatus.OK.value()) {
LOGGER.info(API_SUCCESS);
return API_SUCCESS;
}
} catch (URISyntaxException e) {
LOGGER.error(API_FAIL_URI, e.getMessage());
} catch (InterruptedException e) {
LOGGER.error(API_FAIL_INTER, e.getMessage());
} catch (IOException e) {
LOGGER.error(API_FAIL_IO, e.getMessage());
}
return API_FAILURE;
}
}
Junit :
#Test
public void sendAPICallTest() throws IOException, InterruptedException {
Checkorg test = getCheckOrg();
String portalApiUrl = JUNIT_PORTAL_URL;
String reviewAppsAuthKey = JUNIT_AUTH_KEY;
String message = test.sendAPICall(portalApiUrl, reviewAppsAuthKey);
assertEquals(Checkorg.API_SUCCESS, message);
}
How to mock the HTTP Client in Test Class.
Thank you
As per your comment:
how can we test this method for success if we can't mock
you can use spy for that :
#Test
public void sendAPICallTest() throws IOException, InterruptedException {
Checkorg test = getCheckOrg();
String portalApiUrl = JUNIT_PORTAL_URL;
String reviewAppsAuthKey = JUNIT_AUTH_KEY;
Checkorg mockedTest = Mockito.spy(test);
Mockito.when(mockedTest.sendAPICall(portalApiUrl,reviewAppsAuthKey)).thenReturn("API Call Success");
String message = mockedTest.sendAPICall(portalApiUrl, reviewAppsAuthKey);
assertEquals(Checkorg.API_SUCCESS, message);
}
This can be a quick workaround if HttpClient mocking is not feasible.
I've wrote this simple get request
OkHttpClient httpClient = new OkHttpClient();
StringBuilder url = new StringBuilder(serverURL);
String result = "init";
if(params!=null && params.size()!=0){
url = url.append("?"+prepareParam(params));
}
Request request = new Request.Builder().url(url.toString()).build();
Response response = null;
try {
response = httpClient.newCall(request).execute();
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
catch (Exception e){
e.printStackTrace();
}finally {
response.close();
}
when i tested it on my pc it worked just fine however when i tested it on my mobile it gave me the following exception
java.lang.NullPointerException: Attempt to invoke virtual method 'void okhttp3.Response.close()' on a null object reference
try{
response.close();
}
catch(NullPointerException e){
e.printStackTrace();
}
inside finally block.
Try this out rather then using this many try catch.
OkHttpClient client = new OkHttpClient();
String doGetRequest(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
Then just call above method and pass your url whenever you need.
String response =doGetRequest(yourUrl);
I am trying to send an http post to a given oAuth1.0 protected endpoint, the owner of the endpoint provided to me:
consumerKey
consumerSecret
accessToken
accessTokenSecret
realm
I wrote some code based on How to call API (Oauth 1.0)?
public class HttpAuthPost {
public HttpAuthPost() {
realmID = "XXXXXXX";
String consumerKey = "kjahsdkjhaskdjhaskjdhkajshdkajsd";
String consumerSecret = "jklahsdkjhaskjdhakjsd";
String accessToken = "iuyhiuqhwednqkljnd";
String accessTokenSecret = "oihkhnasdiguqwd56qwd";
setupContext(consumerKey, consumerSecret, accessToken, accessTokenSecret);
}
public void setupContext(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) {
this.oAuthConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
oAuthConsumer.setTokenWithSecret(accessToken, accessTokenSecret);
oAuthConsumer.setSigningStrategy(new AuthorizationHeaderSigningStrategy());
}
public void authorize(HttpRequestBase httpRequest) throws FMSException {
try {
oAuthConsumer.sign(httpRequest);
} catch (OAuthMessageSignerException e) {
throw new FMSException(e);
} catch (OAuthExpectationFailedException e) {
throw new FMSException(e);
} catch (OAuthCommunicationException e) {
throw new FMSException(e);
}
}
public String executeGetRequest(String customURIString, String _content) throws UnsupportedEncodingException {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost httpRequest = null;
//Preparing HttpEntity and populating httpRequest
try {
authorize(httpRequest);
} catch (FMSException e) {
e.printStackTrace();
}
HttpResponse httpResponse = null;
try {
HttpHost target = new HttpHost(uri.getHost(), -1, uri.getScheme());
httpResponse = client.execute(target, httpRequest);
// Process response and generate output
return output;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
I did some tests and I am getting this error: USER_ERROR : header is not NLAuth scheme.
I noticed the realm value is never actually set in the oAuthConsumer configuration, I try to find a way to specify the realm but I have not found a way to do it.
Does anyone have a clue on this?
Well the solution was actually pretty simple and now that I figured it out it seems obvious. Adding the realm as an additional parameter to the authconsumer worked for me.
Hope this help someone else in the future.
public void setupContext(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) {
this.oAuthConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
oAuthConsumer.setTokenWithSecret(accessToken, accessTokenSecret);
oAuthConsumer.setSigningStrategy(new AuthorizationHeaderSigningStrategy());
HttpParameters parameters = new HttpParameters();
parameters.put("realm", realmID);
oAuthConsumer.setAdditionalParameters(parameters);
}
Is there a way to put values into text fields on a webpage from android without loading/showing a WebView? For example, I have two strings and would like to populate two fields on a webpage, is there a way to do this "in the background" or in other words, not having to open a window that the user sees?
Thanks
Update
Found a solution with the help of Tango
This is in my OkHttpHandler class:
public class OkHttpHandler extends AsyncTask<String, Void, String> {
OkHttpClient client = new OkHttpClient();
String cardNumber, privNumber;
public OkHttpHandler(String cardNumber, String privNumber) {
this.cardNumber = cardNumber;
this.privNumber = privNumber;
}
#Override
protected String doInBackground(String... strings) {
RequestBody formBody = new FormBody.Builder()
//Change .add first parameter to the text field you want to populate
.add("CardNbr", cardNumber)
.add("CardPin", privNumber).build();
Request request = new Request.Builder().url(strings[0])
.post(formBody).build();
try {
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code "+ request.toString());
return response.body().string();
} catch (Exception e) {
}
return null;
}
}
A snippet of my MainActivity Class and I print the response to the Log
OkHttpHandler handler = new OkHttpHandler(items.get(0).getNumber(), items.get(0).getPrivNumber());
String result = "";
try {
result = handler.execute("urlHere.com").get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Log.d("returned value", result);
Using OkHttp
final OkHttpClient client = new OkHttpClient();
RequestBody formBody = new FormBody.Builder()
.add("field to be filled", "content")
.build();
Request request = new Request.Builder()
.url("webpage url")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
There is a REST API endpoint which needs to be implemented is used to get some information and send backend request to an another server and response which is coming from backend server has to set the to final response. My problem is how to set response body in javax.ws.rs.core.Response?
#Path("analytics")
#GET
#Produces("application/json")
public Response getDeviceStats(#QueryParam("deviceType") String deviceType,
#QueryParam("deviceIdentifier") String deviceIdentifier,
#QueryParam("username") String user, #QueryParam("from") long from,
#QueryParam("to") long to) {
// Trust own CA and all self-signed certs
SSLContext sslcontext = null;
try {
sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File(getClientTrustStoretFilePath()), "password## Heading ##".toCharArray(),
new TrustSelfSignedStrategy())
.build();
} catch (NoSuchAlgorithmException e) {
log.error(e);
} catch (KeyManagementException e) {
log.error(e);
} catch (KeyStoreException e) {
log.error(e);
} catch (CertificateException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
HttpResponse response = null;
try {
HttpGet httpget = new HttpGet(URL);
httpget.setHeader("Authorization", "Basic YWRtaW46YWRtaW4=");
httpget.addHeader("content-type", "application/json");
response = httpclient.execute(httpget);
String message = EntityUtils.toString(response.getEntity(), "UTF-8");
} catch (ClientProtocolException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}
Here message is the one I need to set. But I tried several methods. Didn't work any of them.
One of the following solutions should do the trick:
return Response.ok(entity).build();
return Response.ok().entity(entity).build();
For more details, have a look at Response and Response.ResponseBuilder classes documentation.
Tip: In the Response.ResponseBuilder API you might find some useful methods that allow you to add information related to cache, cookies and headers to the HTTP response.