I'm trying to create unit tests for my api calls(made via Retrofit 2.0) using Mockito.
This seemed to be the most popular blog on using Mockito with Retrofit.
http://mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html
Unfortunately, it uses earlier versions of Retrofit, and depends on the Callbacks and RetrofitError, which are discontinued from 2.0.
How do you do this with Retrofit 2.0?
P.S.: I'm using RxJava along with retrofit, so something that works with RxJava would be great. Thanks!
on official repository of Retrofit there's an example which can be useful:
https://github.com/square/retrofit/tree/master/retrofit-mock
I've also found: https://touk.pl/blog/2014/02/26/mock-retrofit-using-dagger-and-mockito/
Here you would find this fragment:
Unit Tests
During develop of app, you can send requests the server all time(or
most of time) so it is possible to live without mocked server, it
sucks but is possible. Unfortunately you are not able to write good
tests without the mock. Below there are two unit tests. Actually they
do not test anything but in simple way shows how to mock Retrofit
service using Mockito and Dagger.
#RunWith(RobolectricTestRunner.class)
public class EchoServiceTest {
#Inject
protected EchoService loginService;
#Inject
protected Client client;
#Before
public void setUp() throws Exception {
Injector.add(new AndroidModule(),
new RestServicesModule(),
new RestServicesMockModule(),
new TestModule());
Injector.inject(this);
}
#Test
public void shouldReturnOfferInAsyncMode() throws IOException {
//given
int expectedQuantity = 765;
String responseContent = "{" +
" \"message\": \"mock message\"," +
" \"quantity\": \"" + expectedQuantity + "\"" +
"}";
mockResponseWithCodeAndContent(200, responseContent);
//when
EchoResponse echoResponse = loginService.getMessageAndQuantity("test", "test");
//then
assertThat(echoResponse.getQuantity()).isEqualTo(expectedQuantity);
}
#Test
public void shouldReturnOfferInAsyncModea() throws IOException {
//given
int expectedQuantity = 2;
String responseContent = "{" +
" \"message\": \"mock message\"," +
" \"quantity\": \"" + expectedQuantity + "\"" +
"}";
mockResponseWithCodeAndContent(200, responseContent);
//when
EchoResponse echoResponse = loginService.getMessageAndQuantity("test", "test");
//then
assertThat(echoResponse.getQuantity()).isEqualTo(expectedQuantity);
}
protected void mockResponseWithCodeAndContent(int httpCode, String content) throws IOException {
Response response = createResponseWithCodeAndJson(httpCode, content);
when(client.execute(Matchers.anyObject())).thenReturn(response);
}
private Response createResponseWithCodeAndJson(int responseCode, String json) {
return new Response(responseCode, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", json.getBytes()));
}
Read also: Square retrofit server mock for testing
Hope it help
Related
I try to use MockWebServer to the various responses to my API.
I have made a simple example just to try that what I would like to do is a working method.
Isn't the mockWebServer meant to 'mock' the endpoint of my http connections? Like a real server? Whenever I try to make a call I got UnknownHostException.
Am I using it wrong? Isn't it supposed to just replace a server's response? (mock it)
E D I T:
I have internet permission in manifest.
I use:
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.9.1'
Code:
#Test
public void myTest() throws IOException, InterruptedException {
String url = "http://some-mock-url.com";
MockWebServer server = new MockWebServer();
server.enqueue(new MockResponse().setBody("Something not valid JSON response"));
server.start();
server.url(url);
final CountDownLatch signal = new CountDownLatch(1);
AndroidNetworking.get(url)
.addQueryParameter("some_key", "some_value12345")
.addHeaders("token", "token_1231234")
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
signal.countDown();
Log.i("Response", "jsonObject: " + response);
}
#Override
public void onError(ANError anError) {
signal.countDown();
Log.i("Response", "error: " + anError.getMessage());
}
}
);
signal.await();
}
Logcat:
com.androidnetworking.error.ANError: java.net.UnknownHostException:
Unable to resolve host "some-mock-url.com": No address associated with
hostname
I have found an example when the order is reversed.
So instead of setting an URL to the Mock server, you have to set the Mock server's url to the actual URL, so like:
myAPIsURL= mockWebServer.url("/").toString();
And not
mockWebServer.url(myAPIsURL);
In case someone has the same problem, MockWebServer is from the same dependency of OKHttp so they both need to have the same dependency version.
It was a proxy issue for me .
i followed this solution.
I am not getting the unknown host exception now.
https://stackoverflow.com/a/41714851/5856146
How I use these query in retrofit network call and display it in category wise result
https://api.themoviedb.org/3/genre/{genre_id}/movies
Perhaps this could help:
interface class
public interface TheApiInterface{
#GET("url/bits/until/{path_variable}/then/more/url")
Call<TheThingResponse> getTheThing(#Path("path_variable") String var);
}
Activity or whatever:
public class ThePlaceYoureCallingItFrom {
//set up the api interface and http client
public TheApiInterface getApi(){
String endpoint = "https://api.root.site/api/";
//set up retrofit object
return new Retrofit.Builder().baseUrl(endpoint)
//add chosen converter factory for pojo serialization
.addConverterFactory(GsonConverterFactory.create())
//add the OKHTTP client
.client(new OkHttpClient.Builder().build())
//now gimme
.build().create(TheApiInterface.class);
}
public void callGetTheThing(){
//create call
Call<TheThingResponse> call = getApi().getTheThing("somePathVar");
//set callback
ThingResponseCallback callback = new ThingResponseCallback(this, THING_RESPONSE_INTENT_FILTER);
//fire
call.enqueue(callback);
}
}
the callback:
public class ThingResponseCallback implements Callback<TheThingResponse>{
#Override
public void onResponse(Call<TheThingResponse> call, Response<TheThingResponse> response) {
if (response.isSuccessful() && response.body() != null) {
Log.i(TAG, "onResponse: success: theResponseFieldIWant1: " + response.theResponseFieldIWant1;);
} else {
Log.i(TAG, "onResponse: something went wrong with the response object " +response.body());
}
}
#Override
public void onFailure(Call<TheThingResponse> call, Throwable t) {
Log.i(TAG, "onFailure: to: " + call.request().url() + " req " + call.request());
}
}
the response pojo:
public class TheThingResponse{
#SerializedName("theJsonKeyOfTheFieldReturnedInServerResponse1")
public String theResponseFieldIWant1;
#SerializedName("theJsonKeyOfTheFieldReturnedInServerResponse2")
public String theResponseFieldIWant2;
#SerializedName("theJsonKeyOfTheFieldReturnedInServerResponse3")
public String theResponseFieldIWant3;
#SerializedName("theJsonKeyOfTheFieldReturnedInServerResponse4")
public String theResponseFieldIWant4;
}
the JSON you're receiving would look like this:
{
"theJsonKeyOfTheFieldReturnedInServerResponse1": "the value I wanted 1",
"theJsonKeyOfTheFieldReturnedInServerResponse2": "the value I wanted 2",
"theJsonKeyOfTheFieldReturnedInServerResponse3": "the value I wanted 3",
"theJsonKeyOfTheFieldReturnedInServerResponse4": "the value I wanted 4"
}
but you can build more complex POJOs for more complex JSON.
I've found it useful to make my POJOs all share a Serializable parent class, to make them easy to move about in the Callback, but you could also use a ContentProvider in here quite readily and insert some rows into a DB or something like that if you want to have a more permanent storage.
But bear in mind this is all async- if you want synchronous Retrofit calls, you can use call.execute()
At least in the "retrofit" library, it works like this
#GET("/url/{id}")
suspend fun getNews(
#Path("id") searchById:String
):Response<News>
I am trying to convert this simple response that looks like this
{
"field_one": "bearer",
"field_two": "fgh",
"field_three": 0
}
I am using latest version of Retrofit 2.0.0-beta1. I never used Retrofit before. There are many tutorials and example of old version of Retrofit. I tried different techniques that works with older versions but thats not working with latest one. Due to lack of documentation of latest version of Retrofit I could not find solution.
I want to use latest version.
Here is POJO
public class Auth {
#SerializedName("field_one")
#Expose
private String fieldOne;
#SerializedName("field_two")
#Expose
private String fieldTwo;
#SerializedName("field_three")
#Expose
private Integer fieldThree;
// setter and getter etc. etc.
}
Here is Interface that I am using
interface Authorization {
#Headers("Authorization: This is some header")
#GET("api/v1/mytoken")
Call<Auth> getToken();
}
This is the way I am calling service
OkHttpClient client = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://myendpoint.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
Authorization serviceAuthorization = retrofit.create(Authorization.class);
serviceAuthorization.getToken().enqueue(new Callback<Auth>() {
#Override
public void onResponse(Response<Auth> response) {
Log.d("Response", ">>> "+ response.toString());
}
#Override
public void onFailure(Throwable t) {
Log.d("fail", ">>> "+ t.getMessage());
}
});
I am unable to get output. It just print this
Response: >>> retrofit.Response#2567e2c3
I want to get data in Auth Object that I will use later.
Please suggest me best solution
Thanks!
I guess that you are not seeing you are expecting to see your object printed out on this line --
Log.d("Response", ">>> "+ response.toString());
That is going to call the toString method on the response. If you want to call it on your deserialized object, call the body() method first --
if(response.isSuccess()) {
Log.d("Response", ">>> "+ response.body().toString());
} else {
Log.d("Response", "Error - " + response.code())
}
Alrighty, so I understand that this general question has been asked numerous times here, but I have yet to find an answer that makes sense to me. Almost every answer I've seen just says some blurb like, "hey, just throw this in your method and you're good", but I'm not seeing full examples, and what I've tried is not working either.
Here's the error I receive:
[mono] android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
So, simply put, I have an activity that grabs some information from a web service and then throws the web service results into a couple of TextViews. Could someone please help me figure out where and how I need to use the RunOnUiThread()? Here's the code:
using Android.App;
using Android.OS;
using System;
using System.Web;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using Android.Widget;
namespace DispatchIntranet
{
[Activity (Label = "#string/Summary")]
public class SummaryActivity : Activity
{
private static readonly Log LOG = new Log(typeof(SummaryActivity));
private TextView summaryTotalRegularLabel;
private TextView summaryTotalRollover;
private TextView summaryScheduledLabel;
private TextView summaryRemainingRegular;
private string url;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// SET THE LAYOUT TO BE THE SUMMARY LAYOUT
SetContentView(Resource.Layout.Summary);
// INITIALIZE CLASS MEMBERS
init();
if (LOG.isInfoEnabled())
{
LOG.info("Making call to rest endpoint . . .");
if (LOG.isDebugEnabled())
{
LOG.debug("url: " + this.url);
}
}
try
{
// BUILD REQUEST FROM URL
HttpWebRequest httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(this.url));
// SET METHOD TO 'GET'
httpReq.Method = GetString(Resource.String.web_service_method_get);
// ASK FOR JSON RESPONSE
httpReq.Accept = GetString(Resource.String.web_service_method_accept);
// INVOKE ASYNCHRONOUS WEB SERVICE
httpReq.BeginGetResponse((ar) => {
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse (ar))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
// PUT RESPONSE INTO STRING
string content = reader.ReadToEnd();
// CONVERT STRING TO DYNAMIC JSON OBJECT
var json = JsonConvert.DeserializeObject<dynamic>(content);
if (LOG.isDebugEnabled())
{
LOG.debug("content: " + content);
LOG.debug("json: " + json);
LOG.debug("TOTAL_REGULAR_PTO_HOURS: " + json.d[0].TOTAL_REGULAR_PTO_HOURS);
}
// ** THIS IS WHAT WILL NOT WORK **
this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
}
}
}, httpReq);
}
catch (Exception e)
{
LOG.error("An exception occurred while attempting to call REST web service!", e);
}
}
private void init()
{
// GET GUID FROM PREVIOUS INTENT AND DETERMINE CURRENT YEAR
string guid = Intent.GetStringExtra("guid");
int year = DateTime.Now.Year;
// BUILD URL
this.url = GetString(Resource.String.web_service_url)
+ GetString(Resource.String.ws_get_pto_summary)
+ "?" + "guid='" + HttpUtility.UrlEncode(guid) + "'"
+ "&" + "year=" + HttpUtility.UrlEncode(year.ToString());
// GET THE SUMMARY LABELS
this.summaryTotalRegularLabel = FindViewById<TextView>(Resource.Id.SummaryTotalRegular);
this.summaryTotalRollover = FindViewById<TextView>(Resource.Id.summaryTotalRollover);
this.summaryScheduledLabel = FindViewById<TextView>(Resource.Id.summaryScheduledLabel);
this.summaryRemainingRegular = FindViewById<TextView>(Resource.Id.SummaryRemainingRegular);
}
}
}
When you make a web service call, HttpWebRequest creates a new thread to run the operation on. This is done to keep your user interface from locking up or skip frames. Once your web service call is complete, you need to go back to the UI Thread to update the UI components that live on that thread. You can do that a couple of different ways.
First, you can wrap your code in an anonymous function call like so:
RunOnUiThread(()=>{
this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
});
Or you can call a function via RunOnUiThread (jsonPayload is a field on the class):
jsonPayload = json;
RunOnUiThread(UpdateTextViews);
...
void UpdateTextViews()
{
this.summaryTotalRegularLabel.Text = jsonPayload.d[0].TOTAL_REGULAR_PTO_HOURS;
this.summaryTotalRollover.Text = jsonPayload.d[0].TOTAL_ROLLOVER_PTO_HOURS;
this.summaryScheduledLabel.Text = jsonPayload.d[0].TOTAL_USED_PTO_HOURS;
this.summaryRemainingRegular.Text = jsonPayload.d[0].TOTAL_REMAINING_PTO_HOURS;
}
I've got an application that performs HTTP GET calls using HttpGet and I would like to mock the response in order to test different scenarios without having to setup any specific local server that would act like the remote one.
The goal is to have very high level tests that acts like a real user (Robotium) and fake the response that the application would obtain calling the real server. Much like testing a Twitter client, if you need an example.
Ok, so this is what I did to get fake HttpResponses in my Robotium tests:
- I have a class HttpCallBuilder, that usually just returns a DefaultHttpClient
- I added a setHttpClient() method to set a MockHttpClient in my tests (you need to implement (empty) a lot of methods in the HttpClient interface, which I omitted here):
public class MockHttpClient implements HttpClient {
private static Context context;
private final BasicHttpParams params = new BasicHttpParams();
#Override
public HttpResponse execute(HttpUriRequest request) throws IOException,
ClientProtocolException {
InputStream mockInputStream = context.getAssets().open(
MockResponses.forRequest(request));
return new MockHttpResponse(mockInputStream);
}
#Override
public HttpParams getParams() {
return params;
}
public static void setContext(Context applicationContext) {
MockHttpClient.context = applicationContext;
}
}
MockResponses allows you to prime your Mock with the right responses for the situation:
public class MockResponses {
private static final List<String[]> responseMapping = new ArrayList<String[]>();
private static final String BASE = "mocks/";
public static String forRequest(final HttpUriRequest request) {
final String requestString = request.getURI().toString();
for (final String[] mapping : responseMapping) {
if (requestString.matches(mapping[0])) {
return BASE + mapping[1];
}
}
throw new IllegalArgumentException(
"No mocked reply configured for request: " + requestString);
}
public static void forRequestDoAnswer(final String regex,
final String fileToReturn) {
responseMapping.add(new String[] { regex, fileToReturn });
}
public static void reset() {
responseMapping.clear();
}
}
In your test you can then prepare your test like this:
HttpCallBuilder.setHttpClient(new MockHttpClient());
MockHttpClient.setContext(context);
MockResponses.reset();
MockResponses.forRequestDoAnswer(".*method=Login.*", "loginform.html");
Google provides a library named as Mockwebserver which can be used for mocking web service response. https://code.google.com/p/mockwebserver/ You can refer this link
How about using Mockito ?
According to this article its latest version should support dalvik, so you should be able to use it with robotium.
With mockito you can mock any object to return whatever you want. I found it very powerful and concise.
Try XML Mimic, that will solve your problem. It is easy to configure and runs as independent server.
http://sourceforge.net/projects/xmlmimic/