Unittesting AsyncTaskLoader with getLoaderResultSynchronously - android

I am trying to create unit tests for a REST client that does some API calls. The client works fine in the live application, but I can't get it to run in the test case.
Apparantly, LoaderTestCase.getLoaderResultSynchronously() could be used here (at least according to Android reference, but it will not accept my loader. The code:
public void testGetEventInfo() {
// Init some vars
...
// Create & execute loader
RESTLoader loader = new RESTLoader(getContext(),
RESTLoader.HTTPVerb.GET, action, params, LOADER_GET_NEWS);
getLoaderResultSynchronously(loader);
}
This yields the error getLoaderResultSynchronously(Loader) in the type LoaderTestCase is not applicable for the arguments (RESTLoader).
RESTLoader extends AsyncLoader. Note that I'm using the supportlibrary, maybe the Loader in there is incompatible? The documentation gives no information on this.
I've tried to solve this in several ways, though none seem to work:
Registered a listener to loader. However, the callback never triggers
Using CountdownLatch (also with a listener). Again, no trigger/countdown timeout.
Playing around with the type template (), without success.
Similar solutions on SO, though again failing to reach the listener.
Does anybody know why getLoaderResultSynchronously will not accept the loader? Or another clean way of testing the Loader, including a way to test return data? I can test handling the return data in a separate case, but I would also like to test the actual data.
Sincerely,

Have you taken a look at the source code? You'll find the following import statements:
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
It doesn't look like Android offers a support version for LoaderTestCase. The easiest solution would be to temporarily change to the non-support LoaderManager (that is, have your class make use of the android.content.Loader instead), test your app, and then switch back to the support implementation. You might also consider copying the testing source code into your project, import the support LoaderManager, and execute it directly. I'm not familiar with the test libraries for Loaders but it doesn't seem outwardly obvious that this would cause any major issues.

You can get sources from LoaderTestCase here, create SupportLoaderTestCase class from that sources in your test project and modify all namespaces to support library namespaces (e.g. change android.content.Loader with android.support.v4.content.Loader). Than you can extend your test case from SupportLoaderTestCase (not from LoaderTestCase) and use it without problems

The method you are trying to call (getLoaderResultSynchronously) accepts an object of type android.content.Loader. If your RESTLoader class is not of that EXACT type then you will get this error. I suspect your class directly or indirectly extends android.support.v4.content.Loader, which would explain the error.
I am not aware of a back-port of LoaderTestCase that would support testing of this type of class.

Related

what's the difference between #Mockk and mockk<*>()?

In this Q&A, it says there's no difference. And some people says annotation is better or using constructor(mockk<*>()) is better.
For me, if they are equivalent, less line of code(not using annotation) is better.
Many sample code shows #MockK is used for the values that pass to Class such as ViewModel/Activity or Fragment. On the other hand, mockk<*>() is used for the classes that have its behaviour or data class, etc
There must be some differences since one is annotation and the other is using constructor. And there must be some reasons why each of them are created, not only one of them.
If you know this, could you please answer it?

Avoid a block of code to run during unit test using mokito

I am using Mokitio in android to run unit test cases.
.
What i am trying to do: There is a block of code in onCreate event
of the activity
I am trying not to run this block of code during Running Unit test
cases and run it during app regularly.
Is it possible to do something like that using mokito because mokito synchronizes for activity life cycle
The proper solution here is to change your design a bit. You should not think in terms of code blocks, but in terms of functionality.
The way of preventing that some x lines of code are run in a certain environment, but are not in some other context ... is by using proper OO means.
Meaning: first create an interface that describes the functionality of those lines of code we are talking about:
public interface DoTheFoo {
public void foo(Bar bar);
}
Then you create a "production" implementation DoTheFooImpl of that interface (which as a side effect: you might be able to write proper unit tests for as well).
Finally: within your class that needs that functionality, use dependency injection to acquire an object providing the DoTheFoo interface. In your production environment, that would be a DoTheFooImpl object; but for your unit testing, you would simply create an mock for it - configured to do nothing upen calls to foo().
Of course that sounds like a bit of work; but the point is: currently, your design is somehow deficient. And instead of trying to go for dirty hacks/workarounds, consider looking at your design to identify a more elegant way to resolve your problem.

Rendering issues: The following classes cannot be instantiated

I am converting a Eclipse project to work in Android Studio and have got all issues fixed except some layout xmls are showing the following issue in the drag and drop view
Rendering issues: The following classes cannot be instantiated
X.X.X.myclass.
I checked my class and it seems ok, i changed the latest API i have from the little dropdown; 22 (i guess this is the compile API). I havnt changed my Gradle setup, could it be something in there?
I havnt posted any code as im not sure what would be helpful - any ideas?
First of all: that's just a layout preview. You can edit the XML and carry on with your project and it won't affect anything on it.
The layout rendering thing literally runs your Java classes to create the preview with some mocked implementation or an actual android device, similar to testing mocked implementations.
So this message is just telling you that this mocked system failed to render the preview.
But if you really want to see the preview, you must check where in your class are you relying on variables, or objects that are inherent from your app that the mock system will not have access to.
An example, if your custom view does some special stuff during onLayout:
#Override onLayout(...){
int value = MyLayoutDetailsCalculation.getExtraPadding(getContext());
}
that is a code that is calling to a static method on a separate class that is using the context (probably getting values from system resources or from the display manager) and this will not execute well in a mocked environment and the preview wouldn't be able to render it.
luckly it's an easy fix:
#Override onLayout(...){
int value;
if(isInEditMode()){ // that returns true if this code is being executed by AndroidStudio mocked system.
value = 0; // any value that makes OK for your custom class to properly show a preview
} else {
value = MyLayoutDetailsCalculation.getExtraPadding(getContext());
}
}

Android/Java Standard Package names are they protected

I need to make a reference to a builtin Android Java Class in NDK c++ code.
You can do it by
cls_tm = (*env)->FindClass(env, "javax/crypto/Cipher");
I am worried someone can tamper with apk, extract the java code then create their own class with the package name javax.crypto.Cipher, and read all the sensitive data I am passing to it. I am new to Java and Android so I wanted to know if it is possible to create your own package with same name as built in packages like javax.crypto.Cipher?
It is possible to create classes with the same name. However, they do not take the place of existing classes.
Every class is loaded by a class loader. Class loaders form a hierarchy, with the "bootstrap" class loader at the very top. The class loader that loads your app's classes is created by the Android app framework; it is a child of the "system" class loader, which is a child of the bootstrap loader.
When your app references a class, it asks its class loader to find it by name. Each loader will either return a class that it defined, or ask its parent to find it. (The default behavior is to ask the parent first, but an individual loader can override this.)
javax.crypto.Cipher is part of core.jar, which is loaded by the bootstrap class loader. So unless your application's class loader decides to replace Cipher with its own version, you will get the system version.
(The JNI FindClass call is actually a bit strange. Depending on where you are when you call it, it can actually end up in the system class loader rather than your app's loader. See this section in JNI Tips for an explanation.)
Suppose you really did want to replace Cipher. You can provide your own version, and your app code will happily use it. However, when you try to pass it to some other code in core.jar, your app will fail. This is because classes loaded in the VM aren't unique by name, but rather by the combination of name and class loader. So you can't pass a Cipher+MyAppLoader into something that expects a Cipher+bootstrap.
In any event, if somebody modified your APK, they would have to re-sign it; since they don't have your private key, it wouldn't look like an app that came from you.
If somebody modified a device and replaced the system Cipher with their own version, they can do whatever they want.

Robolectric Custom Shadow Object

OOTB, Robolectric does not support Locales that well. Therefore, if your app is dependent on locales (which a lot of apps are if they are i18n'nd properly) this can be a royal pain. Long story short, I created my own ShadowFooGeocoder and ShadowFooAddress that allow me to simulate the locale I want. They're basically re-implementations of the existing shadows.
However, when I bind my class as such: bindShadowClass(ShadowFooGeocoder.class), this works great. At runtime, the correct shadow is returned. The problem is that I want to set up the simulations on this object and I'm not sure how. shadowOf(instance) where instance is an injected GeoCoder returns ShadowGeoCoder. I've tried working directly with the ShadowWrangler, but that also returns a ShadowGeocoder.
How can I get at my shadowed class that I've bound through the bindShadowClass(...) call so I can set my expectations (simulations)?
Note: This is a repost of the same question on the Robolectric group here. I posted here because my success rate of getting anyone to answer questions on the group is fairly low. I'm hoping for a better result here.
What I've basically done here is extend ShadowGeocoder like this:
#SuppressWarnings({"UnusedDeclaration"})
#Implements(Geocoder.class)
public class ShadowFooBarGeocoder extends ShadowGeocoder {
// implementation stuff
}
Then I would bind it using the bindShadowClasss(...) and when I retreive the shadow via the static shadowOf(...) call I get back a "ShadowGeocoder" which is an instance of ShadowFooBarGeocoder. I then cast it to that type and perform whatever work I need to.

Categories

Resources