How to test AsyncTask class using Mockito - android

I have AsyncTask class as shown below in the code, and I am trying to test it.
I coded the test cases of the AsyncTask as shown below in the testing section, but as shown in the testing code, I just tested whether or not the AsyncTask
methods was called or not, and I did not tested the code in doInBackground() for example, because I do not know how to test it
Please let me know how to test AsyncTask class any guideline or hints are highly appreciated
code
public class AsyncTaskImageLoader extends AsyncTask<String, Void, RequestCreator> {
RequestCreator requCreator = null;
String picUrl = null;
private ImageView mImageView = null;
private UserAdapter.MyViewHolder mHolder = null;
ProgressBar mProgressBar = null;
Validation mValidation = null;
private Context mCtx = null;
public AsyncTaskImageLoader(Context ctx, UserAdapter.MyViewHolder holder) {
mHolder = holder;
mCtx = ctx;
mValidation = new Validation(ctx);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mHolder.progressBar.setVisibility(View.VISIBLE);
}
#Override
protected RequestCreator doInBackground(String... params) {
picUrl = params[0];
if (mValidation.isValidUrl(picUrl)) {
while (!isCancelled() && requCreator == null) {
try {
requCreator = mValidation.requestCreatorFromUrl(picUrl);
} catch (Exception e) {
}
//the value of the delay could be changed preferably
SystemClock.sleep(100);
}
}
return requCreator;
}
#Override
protected void onPostExecute(RequestCreator requestCreator) {
super.onPostExecute(requestCreator);
mHolder.progressBar.setVisibility(View.GONE);
//requestCreator.into(mHolder.imageViewAvatarOfOwner);
mValidation.setImageOnImageView(requestCreator, mHolder.imageViewAvatarOfOwner);
}
testing:
public class AsyncTaskImageLoaderTest {
#Mock
ProgressBar mockProgressBar = null;
#Mock
AsyncTaskImageLoader mockAsyncTaskImageLoader = null;
#Mock
Context mCtx = null;
#Before
public void setUp() {
mCtx = mock(Context.class);
mockProgressBar = mock(ProgressBar.class);
mockAsyncTaskImageLoader = mock(AsyncTaskImageLoader.class);
}
#Test
public void whenProgreeBarISSetToVisibleInOnPreExecute() throws Exception {
mockProgressBar.setVisibility(View.VISIBLE);
verify(mockProgressBar).setVisibility(View.VISIBLE);
}
#Test
public void whenOnDoInBackgroundIsCalled() throws Exception {
String str = new String();
mockAsyncTaskImageLoader.execute(str);
verify(mockAsyncTaskImageLoader).execute(str);
}
#Test
public void whenOnPostExecuteIsCalled() throws Exception {
RequestCreator mockRequestCreator = mock(RequestCreator.class);
mockAsyncTaskImageLoader.onPostExecute(mockRequestCreator);
}
}

Related

Null pointer exception running connected test in Android studio

I am trying to execute connected test for P4, however I am reciing an "Null pointer exception error" for P4
Error message:
:00:02 PM null
java.lang.NullPointerException
at com.android.ddmlib.Client.read(Client.java:692)
at com.android.ddmlib.MonitorThread.processClientActivity(MonitorThread.java:304)
at com.android.ddmlib.MonitorThread.run(MonitorThread.java:256)
It is a standard test, verifying non-empty string in the Async task
Test function:
public void runCloudModuleTest() {
String joke = null;
JokesAsyncTask jokesAsyncTask = new JokesAsyncTask(getContext(), null);
jokesAsyncTask.execute();
try {
joke = jokesAsyncTask.get();
Log.d("CloudModuleTest", "Retrieved a non-empty string successfully: " + joke);
} catch (Exception e) {
e.printStackTrace();
}
assertNotNull(joke);
}
Can someone help me understand what the issue is?
AsyncTask: The Async task pulls data from google cloud engine
public class JokesAsyncTask extends AsyncTask, Void, String> {
private static JokeApi myApiService = null;
private Context mContext;
private String mResult;
private ProgressBar mProgressBar;
public JokesAsyncTask(Context context, ProgressBar progressBar) {
this.mContext = context;
this.mProgressBar = progressBar;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (mProgressBar != null) {
mProgressBar.setVisibility(View.VISIBLE);
}
}
#Override
protected String doInBackground(Pair<Context, String>... pairs) {
if (myApiService == null) {
JokeApi.Builder builder = new JokeApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
.setRootUrl("https://testandroiddevelopment.appspot.com/_ah/api/");
myApiService = builder.build();
}
try {
return myApiService.sendJoke(new JokeBean()).execute().getJoke();
} catch (IOException e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (mProgressBar != null) {
mProgressBar.setVisibility(View.GONE);
}
mResult = result;
startJokeDisplayActivity();
}
private void startJokeDisplayActivity() {
Intent intent = new Intent(mContext, JokeViewActivity.class);
intent.putExtra(JokeViewActivity.JOKE_KEY, mResult);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
I have referenced the variable and it is not an issue due due to the below post, however I did investigate and finally cleaned up and rebuild the project that helped resolved the issue
I have referenced the variable and it is not an issue due due to the post #AxelH, however I did investigate and finally cleaned up and rebuild the project that helped resolved the issue

Async Task - Android Instrumentaion Unit testing - Exception - Only thread created can update the asynctask

This is my Asnyc task class
class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private static MyApi myApiService = null;
private Context context;
private static final String TAG = "EndpointsAsyncTask";
private MainActivity activity;
private ProgressBar mProgressBar;
private Exception mError = null;
private JsonGetTaskListener mListener = null;
InterstitialAd mInterstitialAd;
public EndpointsAsyncTask setListener(JsonGetTaskListener listener) {
this.mListener = listener;
return this;
}
public static interface JsonGetTaskListener {
public void onComplete(String jsonString, Exception e);
}
public EndpointsAsyncTask(MainActivity activity,ProgressBar mProgressBar){
this.activity = activity;
this.mProgressBar= mProgressBar;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// mProgressBar = new ProgressBar(this.activity);
mInterstitialAd = new InterstitialAd(this.activity);
mProgressBar.setVisibility(View.VISIBLE);
}
#Override
protected String doInBackground(Pair<Context, String>... params) {
if(myApiService == null) { // Only do this once
// end options for devappserver
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl("https://backendversionone.appspot.com/_ah/api/");
// https://endpoint-backend-1056.appspot.com/_ah/api/
myApiService = builder.build();
}
context = params[0].first;
String name = params[0].second;
try {
return myApiService.sayHi(name+"check").execute().getData();
} catch (IOException e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
// Toast.makeText(context, result, Toast.LENGTH_LONG).show();
// mProgressBar.setVisibility(View.GONE);
if (this.mListener != null)
this.mListener.onComplete(result, mError);
mProgressBar.setVisibility(View.GONE);
Intent myIntent = new Intent(context, LibraryMainActivity.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
myIntent.putExtra("joke", result);
context.startActivity(myIntent);
}
}
Im trying to test my Async task from test class
Find my class below.
public class MainActivityTest extends ActivityInstrumentationTestCase2 {
private MainActivity mMainActivity;
private TextView mFirstTestText;
ProgressBar pbar;
String mJsonString = null;
Exception mError = null;
CountDownLatch signal = null;
public MainActivityTest() {
super(MainActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
mMainActivity = getActivity();
signal = new CountDownLatch(1);
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
signal.countDown();
}
#MediumTest
public void testcheck(){
Log.d("Testing baby", "Testcheck");
Log.d("Testing baby","Testcheck");
Log.d("Testing baby", "Testcheck");
final Button sendToReceiverButton = (Button)
mMainActivity.findViewById(R.id.buttontelljoke);
assertNotNull(sendToReceiverButton);
}
#SmallTest
public void testchecks(){
Log.d("Testing baby", "Testcheck");
Log.d("Testing baby","Testcheck");
Log.d("Testing baby", "Testcheck");
final Button sendToReceiverButton = (Button)
mMainActivity.findViewById(R.id.buttontelljoke);
assertNotNull(sendToReceiverButton);
}
#MediumTest
public void testasyncTaskTest(){
pbar = (ProgressBar)mMainActivity.findViewById(progressBar1);
try {
EndpointsAsyncTask jokeTask = new EndpointsAsyncTask(mMainActivity,pbar);
jokeTask.setListener(new EndpointsAsyncTask.JsonGetTaskListener() {
#Override
public void onComplete(String jsonString, Exception e) {
mJsonString = jsonString;
mError = e;
signal.countDown();
}
}).execute((new Pair<Context, String>(getActivity(), "")));
signal.await();
assertNotNull(mJsonString);
} catch (Exception e){
fail("Timed out");
}
}
protected Fragment waitForFragment(String tag, int timeout) {
long endTime = SystemClock.uptimeMillis() + timeout;
while (SystemClock.uptimeMillis() <= endTime) {
Fragment fragment = getActivity().getSupportFragmentManager().findFragmentByTag(tag);
if (fragment != null) {
return fragment;
}
}
return null;
}
When running the test case , This line throws exception - Only the created thread can update the Async task
jokeTask.setListener(new EndpointsAsyncTask.JsonGetTaskListener() {
#Override
public void onComplete(String jsonString, Exception e) {
mJsonString = jsonString;
mError = e;
signal.countDown();
}
}).execute((new Pair<Context, String>(getActivity(), "")));
signal.await();
But running the test when my phone is locked, I dont get exception and works fine.
How can i fix this issue.
Not sure if it will helps but try to call
mJsonString = jsonString;
mError = e;
signal.countDown();
in onUiTherad(Runnable)

Android AsyncTask json return value

I have called an async task from my button click.In the doInBackground I have called an API and It is returning me a Json object.I want to pass the Json object to another activity on the button click.How can I can get the return Json object value so that I can send it to other activity.
Thanks.
Create Interface
public interface Listener {
void success(BaseModel baseModel);
void fail(String message);
}
Create Base model class
public class BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
}
Call below method inside your onClick mehtod.
protected void userLoginData(final String userName) {
// if you want to pass multiple data to server like string or json you can pass in this constructor
UserLoginLoader userLoginLoader = new UserLoginLoader(LoginActivity.this, userName, "1234567899", new Listener() {
#Override
public void success(BaseModel baseModel) {
// here you got response in object you can use in your activity
UserLoginModel userLoginModel = (UserLoginModel) baseModel;
// you can get data from user login model
}catch(Exception exception){
exception.printStackTrace();
Utils.showAlertDialog(LoginActivity.this, "Server is not responding! Try Later.");
}
}
#Override
public void fail(String message) {
}
});
userLoginLoader.execute();
}
:- User Login Loader class
public class UserLoginLoader extends AsyncTask<String, Void, Boolean> {
private Dialog dialog;
private Listener listner;
private String deviceId;
Activity activity;
String message;
String userName;
boolean checkLoginStatus;
public UserLoginLoader(Activity activity,String userName, String deviceId, Listener listener) {
this.listner = listener;
this.userName =userName;
this.activity = activity;
this.deviceId = deviceId;
}
#Override
protected Boolean doInBackground(String... arg0) {
//User login web service is only for making connection to your API return data into message string
message = new UserLoginWebService().getUserId(userName, deviceId);
if (message != "null" && !message.equals("false")) {
return true;
}
return false;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new Dialog(activity, R.style.CustomDialogTheme);
dialog.setContentView(R.layout.progress);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
BaseModel baseModel = null;
if (!message.equals("null") && (!message.equals("false")) )
baseModel = parseData(message, result);
if (dialog.isShowing()) {
dialog.dismiss();
dialog.cancel();
dialog = null;
}
if (listner != null) {
if (result && baseModel != null)
listner.success(baseModel);
else
listner.fail("Server not responding! Try agian.");
} else
listner.fail("Server not responding! Try agian.");
}
//call parser for parsing data return data from the parser
private BaseModel parseData(String responseData, Boolean success) {
if (success == true && responseData != null
&& responseData.length() != 0) {
UserLoginParser loginParser = new UserLoginParser(responseData);
loginParser.parse();
return loginParser.getResult();
}
return null;
}
}
This is you Login parser class
public class UserLoginParser {
JSONObject jsonObject;
UserLoginModel userLoginModel;
/*stored data into json object*/
public UserLoginParser(String data) {
try {
jsonObject = new JSONObject(data);
} catch (JSONException e) {
Log.d("TAG MSG", e.getMessage());
e.printStackTrace();
}
}
public void parse() {
userLoginModel = new UserLoginModel();
try {
if (jsonObject != null) {
userLoginModel.setUser_name(jsonObject.getString("user_name")== null ? "": jsonObject.getString("user_name"));
userLoginModel.setUser_id(jsonObject.getString("user_id") == null ? "" : jsonObject.getString("user_id"));
userLoginModel.setFlag_type(jsonObject.getString("flag_type") == null ? "" : jsonObject.getString("flag_type"));
} else {
return;
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
/*return ship name list which is stored into model */
public UserLoginModel getResult() {
return userLoginModel;
}
}
Write a callback method in the Activity that takes in the argument that you wish to pass from AsyncTask to that Activity. Send reference to the Activity to AysncTask while creating it. From doInBackground() method make a call to this callback method with the data your API returns.
Code would be something like -
public class TestAsyncTask extends AsyncTask<Integer, Integer, String[]> {
Activity myActivity;
public TestAsyncTask(Activity activity) {
this.myActivity = activity;
}
#Override
protected String[] doInBackground(Integer... params) {
String data = yourApi();
myActivity.callback(data);
}
}
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new TestAsyncTask(this).execute(someId);
}
public void callback(String data) {
//process data
}
}
Just for the record you can directly get return value from doInBackground() method by calling get() on it.
String data = new TestAsyncTask(this).execute(someId).get();
But note this may block your UI thread as it will wait for the doInBackground() method to complete it's execution.

How to pass asynctask to another activity in android?

I'm try to writing an online game with a socket connection.
So I use asynctask to make a socket connection.
SocketServer.java
public class SocketServer{
private MyCustomListener listener;
private String ip = "127.0.0.1";
private int port = 4444;
#SuppressWarnings("unused")
private Context context;
private SocketAsync socketAsync;
private String dataInput, username;
public SocketServer(Context context) {
this.context = context;
}
public void setOnRecieveMsgListener(MyCustomListener listener) {
this.listener = listener;
}
public void connect() {
socketAsync = new SocketAsync();
socketAsync.execute();
}
public void sentData(String x, String y, String z) {
dataInput = null;
JSONObject object = new JSONObject();
// JSON Encode
socketAsync.sentJSON(object);
}
private class SocketAsync extends AsyncTask<Void, Void, String> {
private Socket socket;
private PrintWriter printWriter;
#Override
protected String doInBackground(Void... params) {
try {
socket = new Socket(InetAddress.getByName(ip),port);
OutputStreamWriter streamOut = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
printWriter = new PrintWriter(streamOut);
streamOut.flush();
BufferedReader streamIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
Looper.prepare();
while(socket.isConnected()) {
try {
dataInput = streamIn.readLine();
listener.onRecieveMessage(new MyListener(dataInput));
}
catch(Exception e) {}
}
Looper.loop();
}
catch(Exception e) {}
return null;
}
public void sentJSON(JSONObject object) {
if(socket.isConnected()) {
try {
printWriter.println(object.toString());
printWriter.flush();
}
catch(Exception e) {}
}
}
}
}
Login.class
public class Login extends Activity implements MyCustomListener {
JSONObject object;
SocketServer socketserver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
socketserver = new SocketServer(this);
socketserver.setOnRecieveMsgListener(this);
socketserver.connect();
button();
}
private void button() {
Button loginBt = (Button)findViewById(R.id.login_bt);
final EditText un = (EditText)findViewById(R.id.username);
final EditText ps = (EditText)findViewById(R.id.password);
final String[] logindata = new String[2];
loginBt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
logindata[0] = un.getText().toString();
logindata[1] = ps.getText().toString();
socketserver.setUsername(logindata[0]);
socketserver.sentData("SERVER", "TEST", "login");
}
});
}
private void toMainScreen() {
Intent x = new Intent(this,Main.class);
startActivity(x);
}
#Override
public void onRecieveMessage(MyListener ml) {
try {
JSONObject json = new JSONObject(ml.getMsgStr());
System.out.println(json.getString("content"));
if(json.getString("content").equals("TRUE")) {
toMainScreen();
}
else
Toast.makeText(getApplicationContext(), "Login Fail", Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
Log.e("## JSON DECODE", e.toString());
e.printStackTrace();
}
}
}
Main.class
public class Main extends Activity implements MyCustomListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//do some thing
}
#Override
public void onRecieveMessage(MyListener ml) {
System.out.println("MAIN : " + ml.getMsgStr());
}
}
so how can I pass object "socketserver" from login class to main class?
or is there an other way to do something like this?
sorry for my poor english.
You should not try to pass an instance of SocketServer around. One of it's properties is context which means you should not used it outside the original context it was created in (i.e. activity it was created in) or you'll have memory leaks.
Your SocketServer class needs IP and port. This is the kind of information that you should pass between activities and then use that to create another instance of your SocketServer class.

Common class for AsyncTask in Android?

I have a common class say for eg Class A which extends AsyncTask and has all the methods implemented i.e. onPreExecute, doinbackground and onPostExecute.
Now, there are other classes which want to use Class A object.
Say Class B uses class A in the below manner
A a = new A(context)
a.execute(url)
Then i fetch the result in get method. But get method is not the proper way of using AsyncTask. I will like to get the result in onPostExecute. For that i tried using a boolean parameter which will get true only in onpostexecute. The class B will check till it gets true and when it gets true it will fetch the result.
But this is somehow blocking the application.
I have placed the code for asynctask below.
'
import java.io.IOException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
public class A extends AsyncTask<String, Void, String>
{
private Context context = null;
private final HttpClient httpClient = new DefaultHttpClient();
private String content = null;
//private String error = null;
private String finalResult = null;
private static boolean isResult = false;
private ProgressDialog progressDialog = null;
public BabbleVilleSyncTask(Context context)
{
this.context = context;
progressDialog = new ProgressDialog(this.context);
}
protected void onPreExecute()
{
progressDialog.setMessage("Please Wait....");
progressDialog.show();
}
protected String doInBackground(String... urls)
{
try
{
//urls[0] = URLEncoder.encode(urls[0], "UTF-8");
HttpGet httpget = new HttpGet(urls[0]);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
content = httpClient.execute(httpget, responseHandler);
}
/*catch(UnsupportedEncodingException ue)
{
error = ue.getMessage();
}*/
catch (ClientProtocolException e)
{
//error = e.getMessage();
cancel(true);
}
catch (IOException e)
{
//error = e.getMessage();
cancel(true);
}
httpClient.getConnectionManager().shutdown();
return content;
}
protected void onPostExecute(String result)
{
finalResult = result;
progressDialog.dismiss();
System.out.println("on Post execute called");
isResult = true;
}
public boolean getIsResult()
{
return isResult;
}
public void setIsResult(boolean flag)
{
isResult = flag;
}
public String getResult()
{
return finalResult;
}
}
'
Can someone let me know what the issue may be?
Regards
Sunil
A clean way to use AsyncTask to get a result would be to use a callback interface.
Here is a simple example of this concept:
interface AsyncTaskCompleteListener<T> {
public void onTaskComplete(T result);
}
then in your B class :
class B implements AsyncTaskCompleteListener<String> {
public void onTaskComplete(String result) {
// do whatever you need
}
public void launchTask(String url) {
A a = new A(context, this);
a.execute(url);
}
}
you should now add the following code to your A class:
class A extends AsyncTask<String, Void, String> {
private AsyncTaskCompleteListener<String> callback;
public A(Context context, AsyncTaskCompleteListener<String> cb) {
this.context = context;
this.callback = cb;
}
protected void onPostExecute(String result) {
finalResult = result;
progressDialog.dismiss();
System.out.println("on Post execute called");
callback.onTaskComplete(result);
}
}
This way, you don't need to wait explicitely for your task to complete, instead, your main code (which is probably the main UI thread), is waiting in the normal android event loop, and the onTaskComplete method will be automatically called, allowing to handle the task result there.
public abstract class BaseTask<T> extends AsyncTask<Object, Void, T> {
public Context context;
public ProgressDialog dialog;
public Exception exception;
protected BaseTask() {
}
public BaseTask(Context context) {
this.context = context;
this.dialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
this.dialog.setMessage(context.getResources().getString(R.string.loading));
this.dialog.show();
}
#Override
protected T doInBackground(Object... objects) {
try {
return doWork(objects);
} catch (Exception e) {
exception = e;
}
return null;
}
#Override
protected void onPostExecute(T result) {
if (dialog.isShowing()) dialog.dismiss();
if (exception == null) {
onResult(result);
} else {
onError();
}
}
public abstract T doWork(Object... objects) throws Exception;
public abstract void onResult(T result);
public abstract void onError();
}
I would make class A a private class embedded in parent class, and once it's done with the work it should update the parent class properties, that's possible onPostExecute.

Categories

Resources