Looking to write some tests for my application, I stumbled upon the Android testing pages. After a fairly long read, it quickly became apparent that the only thing that I could possibly get out of it is information about how to test the UI/Activities. What I really want is the way to test my logic with simply ant test, preferably without even involving the device. I should mention at this stage that I am not using Eclipse and it's quite saddening that 99% of the Java resources on Android assume people do so.
In any case, trying to get anything at all running, I played along with the tutorial as much as I could. It asks that a tests directory is made on the same level as src. Sure, even if every other of their pages implies that the test-project is a completely separate entity. While in the top level project directory, I ran
android create test-project -m /path/to/my/project/ -n MyProjectTest -p tests. It's worth mentioning that they are very inconsistent with saying how they want things to be set up as seen on this question. Visiting the directory, I spot the default testing file. Here's where the issues begin.
To my understanding, testing is done as follows: build application, install; go to tests, build tests, install; run tests from the tests directory using ant test or start them directly using adb shell am instrument. This worked fine. I however have no desire to test the activity but just the logic (which doesn't access any Views/Activities).
Changing the default test to extend AndroidTestClass seemed to have work for a while. The tests were being ran but there were caveats: cleaning tests with ant clean also cleaned the project directory (../tests) so it took forever to build tests in a clean environment (which is necessary because ant debug seems terrible at detecting changes) but it worked and I was happy.
Few more tests later, I get java.lang.VerifyError on my only test class. Googling and Stacking around, it boiled down to either something wrong with external libs or something wrong with my class path. I'm not using any external .jars so it's probably my path.
In any case, here is my question:
what is The Proper Way™ to unit test logic in Android applications with JUnit? I can't find any resources at all concerning this: all resources are either for testing the UI parts or for unit testing ordinary applications.
How can I unit test my logic only? This shouldn't even require a device to run on given that I don't need to use any parts of Android. Where do I place the tests? What do I need to change so that running ant test in my project directory will then run those?
A long mess-around later and I have managed to do it.
First of all, I have ignored any project creation using adb.
Imagine my package is called com.foo.bar. I created tests in src/com/foo/bar/tests. In there, write your regular JUnit tests. Make sure you put package com.foo.bar.tests in your test classes. Here's an example class:
package com.foo.bar.tests;
import com.foo.bar.baz.Foo;
import org.junit.*;
import junit.framework.*;
import static org.junit.Assert.*;
public class MyTests extends TestCase {
public void testSomething() {
Foo testFoo= new Foo();
assertEqual(testFoo.getBar(), 1);
}
}
Next is the case of having the tests run with ant test. To achieve this, add the following to your AndroidManifest.xml just before the last closing bracket (</manifest>):
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.foo.bar"
android:label="Tests for com.foo.bar"/>
You also need
<uses-library android:name="android.test.runner" />
added to your <application> section.
I can't figure out what would need changing to test locally and not on the device but this is 75% of the answer and hopefully will be of help to someone like me in the future.
EDIT:
It's possible to just shadow the original ant test behaviour by adding the following below the last import in build.xml:
<target name="test" >
<junit>
<!-- all your junit stuff here -->
</junit>
</target>
Check out Robolectric — it lets you avoid much of Google's nightmare of a testing solution.
A good article from Square on the subject: The Resurrection of Testing for Android.
Related
For an Android app, I have Robolectric unit-tests. I run them from Eclipse.
I'm using the Robolectric feature of providing a replacement Application class for Robolectric to use. This class, call it TestApplication, extends my application class, call it MyApplication, which extends the Android Application class.
I've found that, when I run individual test cases, Robolectric uses the substitute Application class as expected. But, if I create a run configuration for all the tests in the project, Robolectric reverts to using the Android Application class. It ignores both TestApplication and MyApplication.
What could be causing this? Thanks in advance!
I encountered a similar problem with robolectric where the suite of tests would fail but a single test would run fine. It turned out there was a timing issues while running the suite. Try adding a wait timer or a sleep and see if it works
It seems the cause of the problem was that Robolectric was not using my project's AndroidManifest.xml when Eclipse ran a "run configuration" for a package or an entire project, as opposed to a single test class.
A fix that works is to use Robolectric's configuration feature to provide the location of the manifest. See here.
Both the #Config and properties file solutions worked for me. I preferred the properties file because it applies to the entire project, whereas the annotation has to be on every test class.
The properties file should be named "org.robolectric.Config.properties" and you should put it on your classpath (I did this by placing the file in the test project's source folder).
Assuming you have a TestMyProject containing Robolectric tests for MyProject, the file should contain the following. (The path below is relative to TestMyProject).
manifest=../MyProject/AndroidManifest.xml
I'm trying to get Robolectric up and running by following thecodepath tutorial on github. However, when running the test, eclipse tries to download org/robolectric/android-all/4.3_r2-robolectric-0/android-all-4.3_r2-robolectric-0.jar. What exactly is this 30+ mb .jar file for? Is it supposed to replace the android.jar file from the tutorial?
Let me first ask а question: Why do we need Robolectric for unit testing Android?
And the answer is that android.jar is shipped with contracts of classes and utilities methods only. That means every method, every function and constructor in this jar just have one line of code:
throw new RuntimeException("Stub!");
You can only compile your code against this jar and never run on a desktop JVM. If you try to run then you will get an exception thrown as soon as you try to instantiate an android class or call any android utility method.
Robolectric tries to solve this problem. From the beginning it customises ClassLoader and every call to the android code is replaced with a Robolectric implementation. That gave us possibility to test our code on desktop JVM. But that is quite hard to re-implement whole android as well you trap in situation when you test against something different that is present on devices.
So the strategy was changed from Robolectric version 2. It tries to use as much as possible android source code which is open sourced from the beginning. That is why the first run of your tests Robolectric downloads and caches own android.jar which is compiled from android sources. It is done to make sure that our tests environment behaviour is close to behaviour that we have on the devices.
I would recommend you to read more about Robolectric on their blog, google group. As well you can find plenty of presentations on slideshare and youtube about it. And I encourage you to contribute to Robolectric project on github as soon as you are confident with it and want to give back your gratitude to the community.
I had the same problem when I was trying to set up Robolectric for the first time. The reason for my problem was, my project src files were in the package:
com.example
But my test files were not inside a package. When I moved my test files to:
com.example
The problem got resolved. I hope this might help.
I have an Android project and JUnit tests in my code.
I wanted to know if there is an ant task to run some tests.
In fact, I have several classic tests which are run using JUnit to test several methods, and some tests that need an android emulator or at least need to be run on an android device.
As I didn't find any documentation, I wanted to know if it's possible to do that kind of thing.
Like
junit-android dir="."...
Thanks a lot for your help and time.
Just to be clear because I've search on the web and didn't find many things, so hope you can help.
I have an Android project that contains NO activities.
Actual build.xml file:
I compile java source code
It generates me a .jar file.
I need to run some tests defined in my project/tests/ folder, using
the previous generated library. Thoses tests need to be runned on an
emulator device using ANT build file, whithout being dependent of
Eclipse.
Project:
src (java source code)
gen
bin
res
tests (Android test project)
AndroidManifest.xml
build.xml
...
The test project generated is containing a build.xml that has been automatically generated using android update command. Sadly, there is no task "run-tests". And how do I specify that I would like to use my library for those tests?
Everything you need to create and run android test projects from the command line, provided by Google itself ;-)
http://developer.android.com/tools/testing/testing_otheride.html
The command line you need is something like:
adb shell am instrument -w <test_package_name>/<runner_class>
To call that from Ant, use the <run-tests/> task, described here.
Create a target in your build.xml like this
<target name="run-tests">
<test-junit includedTests="pathToPackageContainingTests}/*.class" />
</target>
Then you can simply do this
ant clean release run-tests
I always prefer ant test command to am instrument to run android tests on my build server, because it's simplier and am instrument doesn't work always.
But so far, I don't know whether if it is possible with ant to run just specific test classes, packages, or suites in order to be more flexible and separate the frequency of run of different test types (like, for example, unit, ui, acceptance, performance etc.).
If there the answer to my question is "no", what else could I do, of course without using am instrument?
Thanks in advance.
You could define a separate Ant target for each type of test, and then make each target conditional on some property.
<target name="performance" if="test.performance">
</target>
You could then execute the required tests by setting the required properties at build time - e.g. by passing on the Ant command line (-Dkey=value) or defining in a properties file which you load in your build file.
I'm a long time Java developer with many years of Java EE, Ant, Maven, unit testing, mocks, etc. I'm currently using gradle to build android apps and am looking at unit testing them. And it's got me tearing my hair out!
My reading indicates that to test an app, I have to create another app inside it in a test directory. But I'm not sure how this embedded app can see the main apps classes. I presume that google came up with this because of something to do with the manifests which are different. I'm not sure why.
Without doing this embedded app system, I've been able to get unit tests to run by including the test classes with the main classes in the APK, adding the instrumentation declarations to the manifest, deploying it and running the test runners. But I don't want to be compiling test classes with app classes and including all the dependencies so that's not really an option and I'm not really sure of the effects of the changes to the manifest as I cannot find any documentation about the effects.
None of this is understood by gradle which follows the maven system of building. Also note that the android way seems to be that the embedded sub-project (test) is dependant on the main parent project, something that is totally contray to gradle and maven.
Another option seems to be separate the test project so that it's completely outside the app project. But really, I'd like to use a similar convention to maven and simply have tests in a separate directory, along with the manifest in test resources.
Has anyone managed to get testing on the emulators running unit tests following a more maven like directory structure?
You can try Robotium. It provides lots of features for a better testcase. You can have a look at it here.
Do you have to run the unit tests in the emulator? Isn't that too slow? I've been using robolectric ( http://pivotal.github.com/robolectric/ ) which creates shadow objects that work similar to mocks. I use progaurd ( http://proguard.sourceforge.net/ ) to strip out the tests for the release build.