Unit Testing With Android Volley
Solution 1:
I implemented a subclass of HttpStack named FakeHttpStack that load fake response body from local file located in res/raw. I did this for development purpose, i.e., I can develop something for new API before server is ready, but you may learn something (e.g., overriding HttpStack#peformRequest and createEntity) from here.
/**
* Fake {@link HttpStack} that returns the fake content using resource file in res/raw.
*/classFakeHttpStackimplementsHttpStack {
privatestaticfinalStringDEFAULT_STRING_RESPONSE="Hello";
privatestaticfinalStringDEFAULT_JSON_RESPONSE=" {\"a\":1,\"b\":2,\"c\":3}";
privatestaticfinalStringURL_PREFIX="http://example.com/";
privatestaticfinalStringLOGGER_TAG="STACK_OVER_FLOW";
privatestaticfinalintSIMULATED_DELAY_MS=500;
privatefinal Context context;
FakeHttpStack(Context context) {
this.context = context;
}
@Overridepublic HttpResponse performRequest(Request<?> request, Map<String, String> stringStringMap)throws IOException, AuthFailureError {
try {
Thread.sleep(SIMULATED_DELAY_MS);
} catch (InterruptedException e) {
}
HttpResponseresponse=newBasicHttpResponse(newBasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK"));
List<Header> headers = defaultHeaders();
response.setHeaders(headers.toArray(newHeader[0]));
response.setLocale(Locale.JAPAN);
response.setEntity(createEntity(request));
return response;
}
private List<Header> defaultHeaders() {
DateFormatdateFormat=newSimpleDateFormat("EEE, dd mmm yyyy HH:mm:ss zzz");
return Lists.<Header>newArrayList(
newBasicHeader("Date", dateFormat.format(newDate())),
newBasicHeader("Server",
/* Data below is header info of my server */"Apache/1.3.42 (Unix) mod_ssl/2.8.31 OpenSSL/0.9.8e")
);
}
/**
* returns the fake content using resource file in res/raw. fake_res_foo.txt is used for
* request to http://example.com/foo
*/private HttpEntity createEntity(Request request)throws UnsupportedEncodingException {
StringresourceName= constructFakeResponseFileName(request);
intresourceId= context.getResources().getIdentifier(
resourceName, "raw", context.getApplicationContext().getPackageName());
if (resourceId == 0) {
Log.w(LOGGER_TAG, "No fake file named " + resourceName
+ " found. default fake response should be used.");
} else {
InputStreamstream= context.getResources().openRawResource(resourceId);
try {
Stringstring= CharStreams.toString(newInputStreamReader(stream, Charsets.UTF_8));
returnnewStringEntity(string);
} catch (IOException e) {
Log.e(LOGGER_TAG, "error reading " + resourceName, e);
}
}
// Return default value since no fake file exists for given URL.if (request instanceof StringRequest) {
returnnewStringEntity(DEFAULT_STRING_RESPONSE);
}
returnnewStringEntity(DEFAULT_JSON_RESPONSE);
}
/**
* Map request URL to fake file name
*/private String constructFakeResponseFileName(Request request) {
StringreqUrl= request.getUrl();
StringapiName= reqUrl.substring(URL_PREFIX.length());
return"fake_res_" + apiName;
}
}
To use FakeHttpStack, you just have to pass it to your RequestQueue. I override RequestQueue too.
publicclassFakeRequestQueueextendsRequestQueue {
publicFakeRequestQueue(Context context) {
super(newNoCache(), newBasicNetwork(newFakeHttpStack(context)));
}
}
Good point for this approach is that, it doesn't require much change in your code. You just have to switch your RequestQueue to FakeRequestQueue when testing. Thus, it can be used in acceptance testing or system testing.
On the other hand, for unit testing, there might be more compact way. For instance, you can implement your Request.Listener subclass as separate class so that onResponse method can be easily tested. I recommend you to put more detail about what you want to test or put some code fragment.
Solution 2:
Take a look at volley tests folder, there you can find examples.
MockCache.java
MockHttpClient.java
MockHttpStack.java
MockHttpURLConnection.java
MockNetwork.java
MockRequest.java
MockResponseDelivery.java
Solution 3:
Not 100% sure that I understand what you want to do, but if I do, then easymock (a lib that allows the creation of mock classes, that you can make calls to and receive predetermined responses) will help you out a lot. A guy called Lars Vogel has a nice article on this topic that I found useful a while back when I used it.
Solution 4:
Here's a copy of the current volley's MockHttpStack mentioned by @Dmytro
package com.android.volley.mock;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.toolbox.HttpStack;
import org.apache.http.HttpResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
publicclassMockHttpStackimplementsHttpStack {
privateHttpResponse mResponseToReturn;
privateIOException mExceptionToThrow;
privateString mLastUrl;
privateMap<String, String> mLastHeaders;
private byte[] mLastPostBody;
publicStringgetLastUrl() {
return mLastUrl;
}
publicMap<String, String> getLastHeaders() {
return mLastHeaders;
}
public byte[] getLastPostBody() {
return mLastPostBody;
}
publicvoidsetResponseToReturn(HttpResponse response) {
mResponseToReturn = response;
}
publicvoidsetExceptionToThrow(IOException exception) {
mExceptionToThrow = exception;
}
@OverridepublicHttpResponseperformRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
if (mExceptionToThrow != null) {
throw mExceptionToThrow;
}
mLastUrl = request.getUrl();
mLastHeaders = newHashMap<String, String>();
if (request.getHeaders() != null) {
mLastHeaders.putAll(request.getHeaders());
}
if (additionalHeaders != null) {
mLastHeaders.putAll(additionalHeaders);
}
try {
mLastPostBody = request.getBody();
} catch (AuthFailureError e) {
mLastPostBody = null;
}
return mResponseToReturn;
}
}
Post a Comment for "Unit Testing With Android Volley"