I run non-Android JUnit tests from within Eclipse every day. Today I wanted to test some of my Android library classes. Oh, the pain.
I have an Android library project using android-maven-plugin. I have source files in src/main/java and my (new) unit test in src/test/java. My POM has the appropriate JUnit dependencies and android-maven-plugin references.
Sometimes I create an Android Uri instance from a File. Sometimes I have an existing Java URI instance that I've created from a File which I then convert to a Uri. Since I trust neither Java nor Android with files and URIs (don't get me started on how Java mangles UNC paths in URIs, or how Java breaks the equals() contract in URIs), I wanted to create a simple unit test to create a temp file, create Uris from two different approaches, and make sure they come out equal.
So I make a little JUnit unit test like I'm used to, and try to run it in Eclipse using Ctrl+F11. Eclipse asks me if this is an "Android JUnit Test" or a "JUnit Test". Well, Android, obviously. So I choose the first option and get:
[2013-03-23 21:37:10 - mylib] ------------------------------
[2013-03-23 21:37:10 - mylib] Android Launch!
[2013-03-23 21:37:10 - mylib] adb is running normally.
[2013-03-23 21:37:10 - mylib] Could not find mylib.apk!
Hmmm... that wasn't very successful. So I delete the run configuration and try just "JUnit Test". Now I get a different dialog, asking me to select my preferred launcher, either "Android JUnit Test Launcher" or "Eclipse JUnit Test Launcher". It doesn't matter which I choose; I get:
Class not found com.example.MyUnitTest
java.lang.ClassNotFoundException: com.example.MyUnitTest
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadClass(RemoteTestRunner.java:693)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.loadClasses(RemoteTestRunner.java:429)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
I've read that with the android-maven-plugin I can run unit tests locally in Eclipse if they just use classes in the Android jar but don't make any API calls, which is what I'm doing here. So how do I pull that off?
A workaround is to click the "Run As..." button in the toolbar and then select "Run Configurations...". If you select the JUnit launcher you created and go to its "Classpath" tab you can add the bin/classes folder to the JUnit launcher classpath. This should now run.
Do not use Run As - Android JUnit Test as it is for running Android Test Project only.
When use Run As - JUnit Test, the ClassNotFoundException is due to inconsistence between ADT and Eclipse built-in JUnit Test Runner regards to the project output folder. ADT generates all .class files under bin/classes, whereas built-in JUnit Test Runner looking for .class files under target/classes. Your Android project in Eclipse never use target/classes so it remains empty, this is the reason why you get ClassNotFoundException exception.
AFAIK there is no way to alter Eclipse built-in JUnit Test Runner to use a different folder than the default target/classes. Check out Ricardo's answer to see how to add bin/classes to built-in JUnit Test Runner's classpath. Also note that you cannot alter your Android project's default output folder to something else than ../bin/classes either, as it will break ADT build process.
The dirty workaround (for solving ClassNotFoundException) is manual copy everything under bin\classes to target\classes, note that you need do this every time you change the source code.
This is not a problem when running mvn test from command line or via Eclipse, as Maven use target\classes and know how to fill it properly. note that by using this approach, you will not able to use the JUnit window with nice red/green error bar inside Eclipse.
An android junit test should be located in a separate module as setup in the Android Maven Plugin samples projects (e.g. the morseflash example). This is due to the overloaded path setting and the need to build the apk and deploy it on the device/emulator to run the test. Android junit tests are NOT unit tests at all, but rather integration test (or in this case called instrumentation tests).
Related
I have several tests in common module for multi platform Kotlin project. When I execute those tests using gradle, e.g. ./gradlew :android:test, they all go through and the tests run.
I have now encountered a more complicated problem where I would like to debug an actual test in IntelliJ. Unfortunately, upon selecting the debug option in IntelliJ, I get an No JDK specified error.
I am using the following dependencies for testing:
testImplementation "org.jetbrains.kotlin:kotlin-test-annotations-common:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-common:$kotlin_version"
with $kotlin_version being 1.2.41.
The common module settings looks like this:
SDKs section also correctly recognises JDKs:
I have tried changing the Module SDK from Kotlin SDK to java, however IntelliJ then wants me to require jUnit for test execution, which I would prefer not to, if possible.
Is there a way how to make the debugger run in IntelliJ for the Kotlin code?
Found the solution.
Just like it does not make sense to execute tests using Gradle in the common module alone, e.g. ./gradlew :common:test and the tests need to be executed for a specific platform ./gradlew :android:test, because the common module might contain expected declarations which are supposed to be implemented per platform using the actual keyword, it also does not make sense to debug in the common module directly.
Instead, for such purposes, the test to be debugged must be placed in a specific platform module, for my purpose I have chosen the Android module, and then it can be executed and debugged.
As I have mentioned, this approach is necessary because in the Android module the expected structures are actually replaced by the actual implementations.
While migrating our build tool to Buck, we stumbled upon the following issues for the unit tests in Android:
Our tests for the view model need to access R.java for asserting the right resources are referenced.
We used the java_test rule but it seems R.java is not found. There is a robolectric_test which builds the .apk but we just want the R.java file in the classpath for the unit tests.
Is there a reason there is no android_test rule.
Any plans of doing so?
We explored the code and looked that we need to see the AndroidLibraryGraphEnhancer and build the Android resources.
Any recommendations?
No plans for adding such rule because it's not clear what it supposed to do and why robolectric_test is not enough.
Buck doesn't build an apk for Robolectric tests.
You really don't want to use java_test to test Android code because Android SDK and Java SDK are different. You have to test Android code with robolectric_test because it uses Android SDK.
On the same android sdk documentation web page:
http://developer.android.com/training/testing/start/index.html#config-local-tests
We can read the following:
"In your Android Studio project,
you must store the source files for local unit tests under a specific source directory
src/test/java"
Lines later:
"In your Android Studio project,
you must place the source code for your instrumentated tests under a specific directory
src/androidTest/java."
So, where are we supposed to put our test sources?
Either or both. They are for different types of tests. The first quote is from a section entitled "Configure Your Project for Local Unit Tests". The second quote is from a section entitled "Configure Your Project for Instrumented Tests". Those are not the same thing.
In a nutshell:
"Local unit tests" means "tests that run on the JVM of your development machine, mostly for testing POJOs, other non-Android-specific code, or Android code that you mock incessantly"
"Instrumented tests" (referred to previously as "instrumentation tests") means "tests that run on Android, and therefore can test code that depends heavily on Android"
This is covered in the Testing Concepts documentation.
In the Android LunarLander sample project, the unit tests are included right in the project, in a (non-source) folder called 'tests'. This is in line with the SDK testing guide which recommends this layout as opposed to creating tests in a separate project. However, I have no idea how I can actually run these tests.
I can't create an Android Junit Test run configuration:
if I try to 'run all test in project or package' it complains that manifest file doesn't contain instrumentation info - clearly it's using the top-level manifest file instead of the tests manifest file.
if I try to 'run a single test', I can't find any because tests isn't a source folder, and if I set it as a source folder, errors pop up, since it assumes the test class should be in a package starting with 'tests.src'.
It's starting to seem to me that this sample is broken... I hope I am wrong, since I'd rather embed tests into my project and be able to run them easily (instead of creating a separate test project that links to project for application under test). Does anybody know how I can run these tests? Thanks...
Google recommend a single all-in-one directory because it makes your files easy maintainable in many situation, for instance when dealing with source control.
It doesn't matter where the test project is located int the file system, however, you must import it into your Eclipse's workspace, same as what you did for the LunarLander project:
If everything goes well, your Package Explorer should look something like this:
In my Android 4.2 samples, things are not going well, it seems that the source code of LunarLander test project is not up-to-date:
it doesn't come with project.properties file.
it uses same package name as LunarLander project, resulting Eclipse to be fooled when importing package/class from the referenced LunarLander project.
it doesn't automatically add the LunarLander project to test project's classpath, resulting imported package/class from the referenced LunarLander project is invisible.
Once you resolve all issues, you should able to run/debug Android JUnit Test from test project.
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