I have a simple AsyncTask that performs some calculations. How can i unit test it?
I don't see why you'd need to test it asynchronously. If your code is in the doInBackground method, you could just call that method from your test class and assert something with the result when it returns.
I had found the following example, I think you should check this out:
https://github.com/pivotal/RobolectricSample
Related
I have a ViewModel in which there is a method which has the following line of code:
billDate.set(!TextUtils.isEmpty(SampleApp.getInstance().getAccountManager().getDueDate()) ?
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due),
SampleApp.getInstance().getAccountManager().getBillingDueDate()) :
SampleApp.getInstance().getApplicationContext().getString(R.string.missing_due_date));
I have a test class using Mockito to test the different methods in ViewModel. But it is failing with NullPointerException at this line:
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due),
Below is the log:
java.lang.NullPointerException
at java.util.regex.Matcher.getTextLength(Matcher.java:1283)
at java.util.regex.Matcher.reset(Matcher.java:309)
at java.util.regex.Matcher.<init>(Matcher.java:229)
at java.util.regex.Pattern.matcher(Pattern.java:1093)
at java.util.Formatter.parse(Formatter.java:2547)
at java.util.Formatter.format(Formatter.java:2501)
at java.util.Formatter.format(Formatter.java:2455)
at java.lang.String.format(String.java:2940)
While running a test case, I see the log showing some error related to Pattern
Can somebody suggest, how to test the String.format() method?
First of all, you should not be importing android view packages into your ViewModel. So skip using things like TextUtils inside ViewModels.
As to the getApplicationContext().getString(), create an interface for this. Something like:
interface StringProvider {
String getString(int resource);
}
Then pass that interface in your ViewModel constructor and use that to get the string you want.
When you initialize the ViewModel, you can pass a concrete implementation of StringProvider like this:
class StringProviderImpl implements StringProvider {
String getString(int resource) {
return SampleApp.getInstance().getApplicationContext().getString(resource);
}
}
This way, for your unit tests, you can just mock StringProvider and don't have to worry about dealing with contexts inside your ViewModel and the related test code.
You don't need to test the String.format method. That is not your code, and your goal should be to test your own code. But your code is using that method, so you need to test your code. This is the part you are trying to validate or mock out as I understand it:
String.format(SampleApp.getInstance().getApplicationContext().getString(R.string.due), SampleApp.getInstance().getAccountManager().getBillingDueDate())
which makes several calls to SampleApp to get an instance. Since those calls to SampleApp.getInstance are static method calls, you won't be able to mock them out. There isn't enough code posted to know what SampleApp is or what SampleApp.getInstance() returns or to know if any of the subsequent calls on that instance are returning null, but one of them is. So I think to solve this you need to look at the what the getInstance method returns. If you can't touch that code and you're hoping to only modify your test classes, you may not be able to test this with mockito due to the static method.
But otherwise you will need to build a way for your tests so the call to SampleApp.getInstance returns a mock object as the instance instead of whatever real instance I presume it is returning now. Then you can mock out the subsequent methods like getApplicationContext and getString to make them return canned responses so that the string.format call will not fail on a null input.
One note of caution--if you do end up making the static getInstance method return a mock, but sure you have proper cleanup when your test is done to set it back to what it was returning originally so you don't inadvertently modify something that might cause another unrelated unit test to fail. That is always a risk if you change something returned by a static method in a unit test since you are effectively changing it for all tests.
Considering that the test fails after the AccountManager was already used, you should have set up the SampleApp as a mock or fake already.
SampleApp app = SampleApp.getInstance()
AccountManager am = app.getAccountManager();
Context context = app.getApplicationContext();
billDate.set(!TextUtils.isEmpty(am.getDueDate()) ?
String.format(context.getString(R.string.due), am.getBillingDueDate()) :
context.getString(R.string.missing_due_date);
Now you only need to make sure to mock the Context you provide with with app.getApplicationContext() or the SampleApp itself, if you use app.getString() directly.
doReturn(dueFormatString).when(context).getString(R.string.due);
doReturn(dueMissingString).when(context).getString(R.string.missing_due_date);
But in general you should abstract the Context away. Not using it will simplify your code and therefore your testing a lot.
Also consider using context.getString() instead of String.format() for formatting a string you load from a resource. It's as easy as adding the format arguments as parameters to the call.
context.getString(R.string.due, am.getBillingDueDate())
I have a function that returns a Completable which returns Completable.error(RuntimeException("message")) if another function fails or Completable.complete() if not.
I was trying to write a unit test for this and see that the flow is going correctly to the error and success code but in my test I cannot differentiate between them using
underTest.unregisterFromService().test().assertComplete().assertNoErrors()
Does anyone know how the Completable.error() value can be checked in unit test?
I believe what you're looking for is
yourCompletable
.test()
.assertErrorMessage("your error message")
There is an assertError for that, most cases use the version that takes the Thorwable's type as a parameter, from the docs:
Asserts that this TestObserver/TestSubscriber received exactly one onError event which is an instance of the specified errorClass class.
Usage:
yourCompletable
.test()
.assertError(RuntimeException::class.java)
Here you can find the three versions of assertError.
I have some requests I'm making with Android Volley. As the Listeners are doing things like turning the response JSON into objects, I'd like to test them to make sure they're doing the right thing. Thing is, I'm not very caught up on how to do unit testing. I do have Robolectric with JUnit set up, but any help would be appreciated. How would I go about setting up my test so I can test the Listener object passed into the request?
It's enough to look at CacheDispatcher:
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
This is where the request's response is created, using abstract parseNetworkResponse method (in case that you have implemented it), and then:
mDelivery.postResponse(request, response);
which actually fires the listeners, if you dig into the code. Rest of the stuff is thread related. I'd reccomend implementing simple testing routine that takes static NetworkResponse, and calls mDelivery's postResponse.
This actually also means, that you could possibly not go this way - it is enough to test which method (Response.success or Response.error) was called - this is your first unit test. Secondly, just test your listeners.
Ok, I have read a lot of questions here on StackOverflow but i still can't understand so i'm opening a new question.
I made a class which function connects to internet and fetches json as string. It works fine in normal Java Application but i can't get it work in my android project.
I'm getting next error: android.os.NetworkOnMainThreadException
So to my understanding I have to use AsyncTask but I don't know how to wrap my function into it.
Function looks like this:
public static String get(String url){
//connect and get data to string
// return string
}
Like I said it works fine in normal JavaApplication but not in android project.
Thx for help!
http://developer.android.com/reference/android/os/AsyncTask.html
Look at the sample
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
}
Your "get" function must be splitted into 2 separate function in this class
what you want to get in, put in
doInBackground
And what you want to do with data which you receive into
onPostExecute
As I understand you use AndroidHttpClient -> so you can not even try to perform your network operations in the UI thread - > so create separate thread for this purpose. You can either use AsynchTask, Thread + Handler or HandlerThread for this purpose, or you can try to experiment here with java.util.concurrent package.
NetworkOnMainThreadException | Android Developers
developer.android.com/... -
Class Overview. The exception that is thrown when an application attempts to perform a networking operation on its main thread. This is only thrown for ...
You can create the thread method which extends AsyncTask (as you correctly understood), and execute it with .execute().
Exactly how you set it up is up to you. Here's a link with a tutorial on spinning these threads:
http://www.vogella.com/articles/AndroidPerformance/article.html#concurrency_threads
I have been having quite a bit of trouble implementing unit testing on the Android. As a simple test, I've been trying to match a string retrieved from string resources:
String myString = myActivity.getResources().getString(R.string.testString));
However, when unit testing this invariably results in a null pointer exception. This includes robolectric as well as the Junit implementation delivered with the Android sdk.
One possible solution is to approach the retrieval of resources in a manner similar to a data access object. That is, create an interface through which string resources would be accessed. This would allow me to mock access the string resource. Similarly, I could separate the non-android dependent behavior of, say, an Activity, into a separate pojo class. This would allow me to run unit tests using standard Java testing tools. In fact, I could potentially delegate any Android infrastructure related activity to an interface.
This seems like a lot of jumping through hoops to get to unit testing. Is it worth it? Is there a more viable approach?
It turned out, the problem was that the activity has to be gotten in the actual test method. So, for example, my method now looks like this:
public void testGetActivityResourceString() {
Activity myActivity = this.getActivity();
String myString = myActivity.getResources().getString(R.string.hello);
Assert.assertNotNull(myString);
}
Whereas before I was creating activity in setup. This giveaway was in the docs:
"For each test method invocation, the Activity will not actually be created until the first time this method is called."
This was a real hassle to figure out. The example for HelloWorldTest doesn't work for the same reason.
Here's the full entry:
Public T getActivity ()
Since: API Level 3
Get the Activity under test, starting it if necessary.
For each test method invocation, the Activity will not actually be created until the first time this method is called.
If you wish to provide custom setup values to your Activity, you may call setActivityIntent(Intent) and/or setActivityInitialTouchMode(boolean) before your first call to getActivity(). Calling them after your Activity has started will have no effect.
NOTE: Activities under test may not be started from within the UI thread. If your test method is annotated with UiThreadTest, then your Activity will be started automatically just before your test method is run. You still call this method in order to get the Activity under test.
This works correctly:
public void testGetResourceString() {
assertNotNull(mActivity.getResources()
.getString(com.example.pkg.R.string.testString));
}
Because you haven't provided any of your code but only the getReousrces() line, I will guess what you are doing wrong:
you are not using the correct base class for your test, use ActivityInstrumentationTestCase2 because you need the system infrastructure
you are using the resources of your test project instead of your project under test, that's why in my example the id is com.example.pkg.R.string.testString.