I am having trouble on how to Mock an external API that an internal API calls.
What I want is basically to test the call on the internal API, to see if it reaches the point of the external API path. I am using Mockito with java and can't seem to get it working. I want to intercept the External API call and return a mock response so the external api isn't hit.
Here is what I have tried:
I am using Micronaut using HttpClients in my tests to do something like:
HttpResponse<blah> response = client.toBlocking().exchange(request, blah.class);
, which is the internal API call. The external api call is in the form of:
HttpResponse<blah> response = client.toBlocking().exchange(request, blah.class, error.class);
I am trying to catch the external API call in my Integration test class by:
when(client.toBlocking().exchange(any(MutableHttpRequest.class), any(Argument.class), any(Argument.class))).thenReturn(resp);
But it seems like I cannot even reach the internal api, the call never seems to be made. I believe that it is being intercepted earlier.
Any help or suggestions are appreciated - I am not sure if this is the right approach or if there's some easier way, but thank you in advance.
Related
I have to modify java based old project(servlet , Gradle project) which was not integrated with any of Java framework. For a recent project integration requirement, needs to call a external Api' PATCH request and change some value(owner ID) time to time on that external api hosted web application.
Endpoint looks like following
https://reverinapi/privivo/api/deys#/v1/drive/maks/{id}
Need to change owner id time to time and JSON should following,
{ "meta": { "ownerId": "smtip|appownid1" } }
I tried following way,
com.google.gson.JsonObject mainObject=new com.google.gson.JsonObject();
com.google.gson.JsonObject meta=new com.google.gson.JsonObject();
meta.addProperty("ownerId", "smtip|appownid1");
mainObject.add("meta", meta);
I don't familiar with how to call the api endpoint and please let me know if there any other efficient way to do this api call and change the value.
You need to use some HTTP client library to make the request. There are likely many available for Java, but Apache's is one.
Ah, I also just learnt that as of Java 11, there's an HTTP client included: https://www.baeldung.com/java-9-http-client.
I am writing Spring Boot Integration test. For this, we boot up the empty application (context) and call multiple services as part of test.
One of the requirements is to call the external REST endpoint with payload that contains an URL to notify (call back) and that service, after some business logic, calls the URL received in the payload.
From the test, I can call the REST endpoint, which is external service. But I want to be able to test the call back from that service for the given URL. URL can be random.
Can I do with MockClientServer? OR MockRestServiceServer Or some other day to test this?
Essentially, I want the test to be able to get an external call and verify it.
After trying out a couple things, WireMock actually does what I wanted. It takes the rest call from outside application(s). Very useful for testing.
I am creating an android app that requires an api call, the api is still in development, but I want to create a dummy retrofit api request that will return an actual json value as response so I can speed up the app development. But now I don't know how to go about it, I have searched online for answers but I don't seems to understand any.
There are a couple of ways to do this.
Using Retrofit/Okhttp mock, you can place the json file in the assets folder and configure retrofit mock/ okhttp mock to serve the json file as the response, when a particular endpoint is hit.
Retrofit Mock [Runs within your app]
https://github.com/square/retrofit/tree/master/retrofit-mock
OKHttp Mock [Runs within your app]
https://github.com/square/okhttp/tree/master/mockwebserver
Json-server [Runs on your PC/Mac]
https://github.com/typicode/json-server
I created endpoint apis but problem is anyone with my project id can go to api explorer and execute those apis. I have put only android client id (using debug keystore) on top of endpoint class declaration but still I can go to incognito mode and execute the apis. How can I restrict the apis so that only my android apps have access and all others will be thrown with some exception?
The APIs can be protected by adding a key parameter that has to be correct for API to be invoked. If the user of the API does not know the key, he won't be able to use the API even with API Explorer.
Advantages of this approach is that it is simple to do, allow you yourself to experiment with the API if you need.
Disadvantages include being very easy to circumvent by a determined user, just by looking at the traffic.
You need to make sure that you have coded your API/backend correctly to only accept the clientId for your app; make sure that you do not see com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID as one of the clientIds in your #Api annotation on the API class:
#Api(
name = "myApi",
version = "v1",
clientIds = {<your android clientId>},
)
public class myApi {
// your API code here
}
If the API Explorer client ID is present, it will allow it to execute your API from the API. I am not 100% sure, but I think you may still see your API form the explorer without the client ID, but execution will be prevented with an error.
This article has more info: https://cloud.google.com/appengine/docs/java/endpoints/auth#Specifying_authorized_clients_in_the_API_backend
You may want to think about putting proper auth around the endpoint calls (i.e. per-user auth checks around each method) if it is particularly sensitive. Just adding a User parameter to the #ApiMethod should be enough for force users to auth before executing each method.
Hope that helps.
You can use on each api allowed_client_ids to be ANDROID_CLIENT_ID only, can be a possible workaround.
I think this could help if you haven't followed it yet : https://cloud.google.com/appengine/docs/python/endpoints/auth#Python_Creating_OAuth_20_client_IDs
Use symmetric key cryptography along with digital signatures for this. However, you'll need to share the key with the Android app first.
Here's how it would work.
Whenever the Android app is making a network request, you take the URL & the parameters, then you Hash it and then encrypt it using the shared private key. You then append the signature as another parameter to the URL.
At the receiving end, your web API will validate whether the request came from your Android app ONLY.
Please note, that this will work ONLY for your app. It will not work as a way to catch all generic Android requests/
Here are some points for consideration :
Cloud Endpoints has been supporting the ANDROID CLIENT ID and
package signing, so that should atleast take care of the fact that
only a signed Android application from your side can access the
endpoint
.
If you wish to remove the Web Clients from access, then I would
probably look into the HTTP Headers and Agents to see if there is a
sure way of identifying these web clients.However, this would
require that you write your own Authorization logic in the method
since I do not believe that the endpoints infrastructure can take
care of this automatically for you
.
Remove access for everyone via the Annotations could be
problematic if you want a quick way to use the API Explorer to test
out the API. So do keep the API Explorer access available.
I have Java servlets that rely on the Channel API, from Google App Engine. I am trying to write unit tests for that code, but I am quite stumped with how to write a stub client to receive a response message from the servlet, instead of me always having to rely on using an actual web page as my test client. My servlet is quite simple:
ChannelService channelService = ChannelServiceFactory.getChannelService();
channelService.sendMessage(new ChannelMessage(someKey, "ECHO: " + someMsg));
Usually, I read this in my test client, which is a web page. But, I want to write unit tests that I can test using a framework like jUnit or TestNG. After reading Google's page about unit testing their Java services, I tried stuff such as using a LocalServiceTestHelper object in my test class and configure it with a LocalChannelServiceTestConfig object. The result of this is that my test class can create an instance of LocalChannelService, a class which seems to implement the same methods as ChannelService.
However:
Neither classes have any robust relationship to each other (don't implement a similar interface, are not in the same class hierarchy...). Makes it impossible for me to inject a LocalChannelService object into my servlet as a mock object.
No documentation whatsoever on LocalChannelService API (Thanks a lot, Google).
Also no documentation on their Local Unit Testing page for how to test the Channel API (again, thanks a lot Google)
So then I came across this post about how to test ChannelService in Java code. Unfortunately, the only relevant answer given was for Python. Well, lo and behold, Google indeed does provide Python GAE server developers with tools for writing stub clients for Google services, as outline in their Python Local Unit Testing guide. Unbelievable how they neglected to do the same for Java!
Now that I've gotten all that off my chest (apologies if I sounded a bit too flustered), I would really like to know, what is the best way for testing Java code relying on Google App Engine's Channel API? I really wish to rely on testing tools instead of web pages. do I have to somehow call Google's Javascript Client for Channel API from Java? There must be a better way in which I can use a mock object or stub.
Update 1
Used a better name, "Google App Engine" instead of just "App Engine"
You can get the LocalChannelService from the LocalServiceTestHelper, connect a fake client to it, then get the message from it:
LocalChannelService svc = (LocalChannelService) LocalServiceTestHelper.getLocalService("channel");
ChannelManager channelManager = svc.getChannelManager();
String connectionId = channelManager.connectClient(token);
// send a message
String message = channelManager.getNextClientMessage(token, connectionId);
assertEquals("123", message);
These are just my thoughts on unit testing the Channel API:
You don't need a mock.
Just use the actual API. Just pretend that it works. It doesn't return any failure even if your message fails to send, so you can't test for that anyways.
Have a backup.
I don't think you can rely on the Channel API. Messages fail to appear. I personally believe you need a backup, like a polling API that isn't as responsive as the Channel API, but at least works.
Unit test your backup API.
Use Selenium to test the Channel API in a browser.