JUnit Testing in Android

Put your problem here if it does not fit any of the other categories.

JUnit Testing in Android

Postby IcedDante » Tue Feb 02, 2010 12:26 pm

Struggling through some complicated trigonometric functionality in my Android app, I realized Unit-Testing based development was the way to go so I spent a few hours writing JUnit test cases for many of my back-end classes. These classes are, for the most part, removed from the Android SDK, but they do reference some of the 2D drawing classes under Drawable.

Well, I guess that was enough because when I tried to run the TestCase as a JUnit test case I got an error:
Cannot connect to VM
socket closed


Unit testing still worked in my non-android projects, so I guessed that the problem was that I couldn't run any code that uses android.jar as a TestCase... I had to specify it as AndroidTestCase. Am I wrong? I made this change, tried to run the configuration... and failed:

An instrumention[sic] test runner is not specified


Welcome to the world of Unit Testing with AndroidTestCase. I have been downloading code snippets to try to get a better handle on how this framework works but either it's more complicated than I thought it would be, or there is no good documentation for putting together these types of cases as I've spent the better part of the day googling AndroidTestRunner, TestSuite, and trying to figure out how they fit together.

Do I have to create a separate Activity to run these tests, or is it possible to use a TestRunner in some way to just run my unit tests on the back-end classes?

I can post one of my back-end data classes with the corresponding TestCase if necessary.
IcedDante
Junior Developer
Junior Developer
 
Posts: 11
Joined: Wed Jan 20, 2010 8:45 am
Location: San Diego

Top

Postby Johan Degraeve » Tue Feb 02, 2010 4:21 pm

do you have included what's in the instrumention tag below in your manifext.xml ?
source

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4.    package="com.example.app.tests" android:versionCode="1"
  5.    android:versionName="1.0">
  6.     <application>
  7.        <uses-library android:name="android.test.runner" />
  8.     </application>
  9.     <uses-sdk android:minSdkVersion="3" />
  10.        
  11. <instrumentation android:name="android.test.InstrumentationTestRunner"
  12.       android:targetPackage="com.example.app" android:label="Tests for My App" />
  13. </manifest>
Parsed in 0.001 seconds, using GeSHi 1.0.8.4
regards,

Johan
Johan Degraeve
Experienced Developer
Experienced Developer
 
Posts: 55
Joined: Tue Oct 27, 2009 1:50 pm
Location: Belgium

Postby IcedDante » Tue Feb 02, 2010 7:42 pm

Well, my test code is part of my project, so how can I have two manifest.xml files? Please explain how that works.

Currently I have two source folders, src, which has my main app source code, and tst, which is where I have my UnitTesting code and any other related files. Do I need to create a separate project instead? I think it would be cleaner to keep them in the same space.

I guess my main question is this:

What is the simplest way to run Unit Test Cases that do not reference the context or the view in any way?

It seems that I should be probably be using the ActivityUnitTestCase for these purposes other than the AndroidTestCase class so I am looking into having my test cases extend this class.

Thanks for the help.
IcedDante
Junior Developer
Junior Developer
 
Posts: 11
Joined: Wed Jan 20, 2010 8:45 am
Location: San Diego

Postby Johan Degraeve » Tue Feb 02, 2010 9:54 pm

you can keep your Testcase Classes in the same src folder as your classes under test, this accounts for AndroidTestCase and junit TestCase

If you don't need the reference to the Context in your classes under test, then there's no need to use AndroidTestCase, you canuse junit TestCase

In case you use AndroidTestCase , you can use this instrumentation tag in the AndroidManifest.xml also just for running the emulator, there's no need to have two versions of AndroidManifest.xml
regards,

Johan
Johan Degraeve
Experienced Developer
Experienced Developer
 
Posts: 55
Joined: Tue Oct 27, 2009 1:50 pm
Location: Belgium

Postby IcedDante » Wed Feb 03, 2010 1:18 am

Johan Degraeve wrote:If you don't need the reference to the Context in your classes under test, then there's no need to use AndroidTestCase, you canuse junit TestCase


I will say that in my experience this is somewhat incorrect. Because the JUnit TestCase may be testing classes that use the android.jar file, attempting to run these tests as a JUnit Configuration will throw a VM error. It is necessary to modify the bootstrap launch configuration to remove the android.jar as is described here.

Okay, here is where I am at:

I have a TestCase (edited for brevity)

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.grafightscratch.ochemmer.molecules;
  2.  
  3. import com.grafightscratch.ochemmer.MoleculeTablet;
  4.  
  5. import android.graphics.Canvas;
  6. import android.graphics.Point;
  7. import android.graphics.Rect;
  8. import android.graphics.drawable.ShapeDrawable;
  9.  
  10. public abstract class VisualObject {
  11.         protected double orientation; //0-360 degree orientation
  12.  
  13.         private int velocity; //Pixels per frame speed this is moving at
  14.         private Rect boundingBox;
  15.         private ShapeDrawable mSDraw;
  16.        
  17.         public VisualObject() {
  18.                 boundingBox = new Rect();
  19.         }
  20.        
  21.  
  22.         protected Rect getBoundingRect() {
  23.                 return boundingBox;
  24.         }
  25.        
  26.         public void toggleSelect() {
  27.                 if(selected) selected = false;
  28.                 else selected = true;
  29.         }
  30.        
  31.         protected void setBoundingRect(int x, int y, int xWidth, int yWidth) {
  32.                 boundingBox.set(x, y, x+xWidth, y+yWidth);
  33.         }
  34.        
  35.         protected void setBoundingSquare(int x, int y, int width) {
  36.                 setBoundingRect(x, y, width, width);
  37.         }
  38.        
  39.         protected void setBoundingRect(Rect newRec) {
  40.                 boundingBox = newRec;
  41.         }
  42.        
  43.         public Point getPosition() {
  44.                 return new Point(boundingBox.left, boundingBox.top);
  45.         }
  46.        
  47.         public void moveBy(float x, float y) {
  48.                 Rect nRec = null;
  49.                 Rect oRec = getBoundingRect();
  50.                
  51.                 nRec = new Rect((int)(oRec.left+x), (int)(oRec.top+y), (int)(oRec.right+x), (int)(oRec.bottom+y));
  52.                
  53.                 setBoundingRect(nRec);
  54.         }
  55.        
  56.         public void moveTo(int x, int y) {
  57.                 Rect oldRec = getBoundingRect();
  58.                 oldRec.left = x;
  59.                 oldRec.top = y;
  60.                 //TODO: handle bottom right?
  61.         }
  62.        
  63. }
  64.  
Parsed in 0.013 seconds, using GeSHi 1.0.8.4


And a corresponding test case:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.grafightscratch.ochemmer.molecules.tst;
  2.  
  3. import android.graphics.Point;
  4. import android.test.ActivityUnitTestCase;
  5.  
  6. import com.grafightscratch.ochemmer.molecules.VisualObject;
  7. import com.grafightscratch.ochemmer.MoleculeTablet;
  8.  
  9. public class VisualObjectTest extends ActivityUnitTestCase<MoleculeTablet> {
  10.         VisualObjectTestImpl obj;
  11.  
  12.         public VisualObjectTest(Class<MoleculeTablet> activityClass) {
  13.                 super(activityClass);
  14.         }
  15.         protected void setUp() throws Exception {
  16.                 obj = new VisualObjectTestImpl();
  17.                 obj.moveTo(100, 200);
  18.         }
  19.  
  20.         public void testMoveTo() {
  21.                 fail("Not yet implemented");
  22.                 Point point = obj.getPosition();
  23.                 assertEquals(100, point.x);
  24.                 assertEquals(200, point.y);            
  25.         }
  26.        
  27.         public void testMoveBy() {
  28.                 obj.moveBy(20, 45);
  29.                 Point point = obj.getPosition();
  30.                 assertEquals(120, point.x);
  31.                 assertEquals(245, point.y);
  32.         }
  33.  
  34.  
  35.         public void testContains() {
  36.                 fail("Not yet implemented");
  37.         }
  38.        
  39. }
  40.  
Parsed in 0.011 seconds, using GeSHi 1.0.8.4


Both of these classes exist in the main project with my Android app but are in a second source folder I call "tst". I also defined a TestSuite for the hell of it but I don't know if this is necessary:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package com.grafightscratch.ochemmer.molecules.tst;
  2.  
  3. public class AllTests extends junit.framework.TestSuite {
  4.  
  5.         public AllTests() {
  6.                 addTestSuite(VisualObjectTest.class);
  7.         }
  8. }
  9.  
Parsed in 0.011 seconds, using GeSHi 1.0.8.4


And modified my manifest according to your instructions:
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.      package="com.grafightscratch.ochemmer"
  4.      android:versionCode="1"
  5.      android:versionName="1.0">
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">
  7.         <activity android:name=".MoleculeTablet"
  8.                  android:label="@string/app_name">
  9.             <intent-filter>
  10.                 <action android:name="android.intent.action.MAIN" />
  11.                 <category android:name="android.intent.category.LAUNCHER" />
  12.             </intent-filter>
  13.         </activity>
  14.                 <uses-library android:name="android.test.runner" />
  15.     </application>
  16.    
  17.     <uses-sdk android:minSdkVersion="3" />
  18.        
  19.         <instrumentation android:name="android.test.InstrumentationTestRunner"
  20.       android:targetPackage="com.grafightscratch.ochemmer.molecules.tst" android:label="Molecule Modeller" />
  21. </manifest>
Parsed in 0.001 seconds, using GeSHi 1.0.8.4


With all this in place, I right click on my VisualObjectTest and set up a configuration for it as an Android JUnit Test. It points to my Instrumentation Runner, but when I tell it to go I get an error message:
Test run failed: Unable to find instrumentation target package: com.grafightscratch.ochemmer.molecules.tst android.util.AndroidException: INSTRUMENTATION_FAILED: com.grafightscratch.ochemmer/android.test.InstrumentationTestRunner


Any ideas where I go from here? Ironically I have wasted more time trying to debug my test code than I have trying to debug my application :(

Still, I am sure that once (if?) I get this process down I will be able to code more efficiently. Hopefully it will help others too.
IcedDante
Junior Developer
Junior Developer
 
Posts: 11
Joined: Wed Jan 20, 2010 8:45 am
Location: San Diego

Postby IcedDante » Wed Feb 03, 2010 11:34 pm

Alright- I discovered the source of my error. It was in my manifest file where I declare my instrumentation's targetPackage:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1.         <instrumentation android:name="android.test.InstrumentationTestRunner"
  2.       android:targetPackage="com.grafightscratch.ochemmer.molecules.test" android:label="Molecule Modeller" />
  3.  
Parsed in 0.000 seconds, using GeSHi 1.0.8.4


The targetPackage attribute can be misleading. It isn't asking for the java namespace package, it is asking for the package that is deployed to the emulator. You can retrieve a list of packages through

adb shell pm list packages


My package name is just com.grafightscratch.ochemmer and changing android:targetPackage fixed this problem. I then right click on the project name in my Eclipse explorer, Run As->Android JUnit Test, and it works fine.
IcedDante
Junior Developer
Junior Developer
 
Posts: 11
Joined: Wed Jan 20, 2010 8:45 am
Location: San Diego

Top

Re: JUnit Testing in Android

Postby candydhami » Tue Feb 22, 2011 10:03 am

Hi, i wan to run a single testcase with different parameters. in java it possible through junit4 and code is like this package com.android.test;

import static org.junit.Assert.assertEquals;

import java.util.Arrays; import java.util.Collection;

import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class) public class ParameterizedTestExample {

private int number;
private int number2;
private int result;
private functioncall coun;

//constructor takes parameters from array
public ParameterizedTestExample(int number, int number2,
int result1) {
this.number = number;
this.number2 = number2;
this.result = result1;
coun = new functioncall();
}

//array with parameters
@Parameters
public static Collection<Object[]> data() {
Object[][] data = new Object[][] { { 1, 4, 5 }, { 2, 7, 9 },
{ 3, 7, 10 }, { 4, 9, 13 } };
return Arrays.asList(data);
}
//running our test
@Test
public void testCounter() {
assertEquals("Result add x y", result, coun.calculateSum(this.number, this.number2), 0);
}

}
i have android project in that i have android testcase, i need to run that test case with different parameter like shown above in java parmeterized testcase class.above given annotation like "@Test" and "@Parameters" are defined in junit 4, where as android uses junit3 for running testcase, so is there any way by which i can run the android testcase like above.
candydhami
Freshman
Freshman
 
Posts: 2
Joined: Tue Feb 22, 2011 8:26 am

Top

Return to Other Coding-Problems

Who is online

Users browsing this forum: No registered users and 5 guests