I'm trying to setup unit tests inside Android Studio (which supposedly is still 'experimental'). How do I get a Context? All the examples I see call AndroidTestCase.getContext() but in my tests this returns null.
public class DummyTest extends AndroidTestCase {
public void testExample() throws Exception {
Context c = getContext();
assertNotNull(c);
}
}
This will result in a AssertionFailedError because the returned context is null.
Related
I've started learning android unit tests, but it looks very hard to find some good guides or information. Every example have a stupid example about 2+2 = 4
Say I write a little SDK which has few functions
MySdk.Init(Context context)
MySdk.CallTask()
I create an androidTest file
How should I call my SDK functions to check how they work? Somewhere required parameters like int/string/context. I just really don't understand, please help me.
This is what I've tried
public class AndroidTest {
private Activity context;
//default test
#Test
public void addition_correct() throws Exception {
assertEquals(4, 2 + 2);
}
#Test
public void checkContext() {
context = getActivity();
assertNotNull(context);
}
#Test
public void testInitPhase() {
MySdk.Init(context, new SdkInitializationListener() {
#Override
public void onInitializationSuccessful(String adv_id) {
assert (adv_id != null);
}
#Override
public void onInitializationError() {
}
});
}
}
For context i was tried context = new mockContext();. It's passed as context = null and my SDK failed with initialization.
Unit tests are mainly about testing an individual class in isolation, so that you can check if individual public methods of a class behave as you intend them to, and continue to do so if you change that class' code in the future. Let's say you have a class like this:
public class UtilityFunctions {
public int double(int value) {
return value * 2;
}
public String mirror(String value) {
if (value == null) return "";
return value + new StringBuilder(value).reverse().toString();
}
}
You want to test these two methods with:
valid input values, and check the output is as expected
invalid values, and check that errors are handled accordingly (and the correct exceptions thrown if necessary)
So a test class for the above class may look like this
#RunWith(JUnit4.class)
public class UtilityFunctionsTest {
private UtilityFunctions utility;
#Before
public void setUp() {
// Initialises any conditions before each test
utility = new UtilityFunctions();
}
#Test
public void testDoubleFunction() {
assertEquals(2, utility.double(1));
assertEquals(8, utility.double(4));
assertEquals(-12, utility.double(-6));
assertEquals(0, utility.double(0));
}
#Test
public void testMirror() {
assertEquals("", utility.mirror(null));
assertEquals("", utility.mirror(""));
assertEquals("aa", utility.mirror("a"));
assertEquals("MirrorrorriM", utility.mirror("Mirror"));
}
}
These standard Java unit tests are run from the test directory. However, you'll need to run tests in the androidTest directory whenever you're using Android-specific classes such as Context. If you're creating a MockContext, you're simply creating an empty Context whose methods don't do anything.
Without me knowing anything about what your MySDK does, I think you may need to pass a fully-functioning Context into your class for your tests. The Android JUnit runner does provide this with InstrumentationRegistry.getTargetContext(), so for your example, you may need to add this #Before method:
#Before
public void setUp() {
context = InstrumentationRegistry.getTargetContext();
}
You'll also need to remove the context = getActivity(); line from your first test.
I don't understand why View.getContext() returns null in this case:
#Mock
Context mContext;
#Mock
SensorManager mSensorManager;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
//...
#Test
public void initWithContext() throws Exception {
assertNotNull(mContext);
assertNotNull(mSensorManager);
when(mContext.getSystemService(Context.SENSOR_SERVICE)).thenReturn(mSensorManager);
ImageView imageView = new ImageView(mContext);
assertNotNull(imageView);
assertNotNull(imageView.getContext()); // Error because getContext() is null
}
First lines of View constructor:
public View(Context context) {
mContext = context;
Method getContext()
#ViewDebug.CapturedViewProperty
public final Context getContext() {
return mContext;
}
I am not mocking the ImageView, why View.getContext() returns null then?
EDIT
when(imageView.getContext()).thenReturn(mContext);
assertNotNull(imageView.getContext()); //Error, imageView.getContext() returns null
If these are pure JVM unit tests (i.e. run on your computer's JVM and not on an Android emulator/device), then you have no real implementations of methods on any Android classes.
You are using a mockable jar which just contains empty classes and methods with "final" removed so you can mock them, but they don't really work like when running normal Android.
See more here: https://developer.android.com/training/testing/unit-testing/local-unit-tests.html#mocking-dependencies
I guess your issue is what #wojtek explained, you're running local unit tests, you can mock something like using the context to retrieve some resource.
If you need to test your views behavior and mocking the Android APIs in the same time, I would suggest trying Robolectric framework
I try to mock a method in my instrumentation test but it fails and I am looking for a solution to solve it.
public class MyTest extends InstrumentationTestCase {
private Context mAppCtx;
#Override
public void setUp() throws Exception {
super.setUp();
Context context = mock(Context.class);
mAppCtx = getInstrumentation().getContext().getApplicationContext();
when(mAppCtx.createPackageContext(PACKAGE_NAME, 0)).thenReturn(context);
}
A crash happens on the following line:
when(mAppCtx.createPackageContext(PACKAGE_NAME, 0)).thenReturn(context);
And I got following error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
You need to mock each method invocation of: getInstrumentation().getContext().getApplicationContext();
Example:
Instrumentation inst = mock(Instrumentation.class);
Context instContext = mock(Context.class);
ApplicationContext mAppCtx= mock(ApplicationContext.class);
when(getInstrumentation()).thenReturn(inst);
when(inst.getContext()).thenReturn(instContext);
when(instContext.getApplicationContext()).thenReturn(mAppCtx);
when(mAppCtx.createPackageContext(PACKAGE_NAME, 0)).thenReturn(context);
What I'm trying to do is implement a unit test, but I need to clear the database before it.
The problem is that sometimes clearing database fails with NullPointerException.
Basicily I call deleteAll method on every DTO I have (for example BusinessUnit.deleteAll(BusinessUnit.class). And sometimes this fail (though not always).
Null pointer originates from SugarRecord's own method:
public static <T extends SugarRecord<?>> void deleteAll(Class<T> type) {
Database db = SugarApp.getSugarContext().getDatabase();
SQLiteDatabase sqLiteDatabase = db.getDB(); // exception is thrown here
sqLiteDatabase.delete(getTableName(type), (String)null, (String[])null);
}
What could have caused this error?
Let the sugarorm start up at first. You have first to let start the SugarOrm. This task needs some time. Therefore add the following:
public class ApplicationTest extends ApplicationTestCase<Application> {
#Override
public void setUp() throws Exception {
super.setUp();
// SugarORM need some time to start up, else tests will fail
Thread.sleep(3000);
}
When i am wrtting
#Before
public void setUp() throws Exception {
Activity activity = Robolectric.buildActivity(ActivityMain.class).create().get();
}
and after running the test Its giving me error org.fest.reflect.exception.ReflectionError: Unable to find method '$$robo$getData' I am using eclipse and ant build for testing the robolectric test for android.
But this code is working fine with my test
#Test
public void testBasicResourceValue() throws Exception {
String helloFromActivity = new ActivityMain().getResources().getString(R.string.str_my_file);
assertThat(helloFromActivity, equalTo("newfile"));
}
so its confirmed that the program is able to get the AndroidManifest.xml
Activity activity =
Robolectric.buildActivity(ActivityMain.class).create().get(); this
line is not working with ANT build i dont know why? i heard
robolectric is stopped supporting ANT.So i found a another workaround
for this problem to get the shadow object of the activity by using
this code given below
#Before
public void setUp() throws Exception {
MyActivity activity = new MyActivity();
//Remember setContentView() has to call before you are trying to get any resource ID from the activity like Button,TextView etc other wise you will get the not shadow object for those views.
activity.setContentView(R.layout.warning);
Assert.assertNotNull(activity);
}