Android tests documentaton - android

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.

Related

Running multi platform Kotlin test in IntelliJ produces No JDK specified error

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.

Simple non-API Android JUnit test in Eclipse with android-maven-plugin?

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).

Android unit testing - how to run tests in same project as application?

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.

Trying to understand android testing

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.

How to test an Android Library Project

I am writing an Android Library Project basing on Android Bitmap class (call it AndroindLib) which contains only utility class (no activity). I tried to test it using Android JUnit, but it keeps complaining that can't find the AnroidLib.apk
What's the right way to Unit test Android Library Project?
Quoting the documentation:
"There are two recommended ways of setting up testing on code and resources in a library project:
You can set up a test project that instruments an application project that depends on the library project. You can then add tests to the project for library-specific features.
You can set up a standard application project that depends on the library and put the instrumentation in that project. This lets you create a self-contained project that contains both the tests/instrumentations and the code to test."
In your test project simply change the package name so that it's the same as your library's package.
For example, you have a library whose package is "com.example.lib". Create a test project targeting your library. In the manifest file you'll see package="com.example.lib.test", and targetPackage="com.example.lib". Just change the package from "com.example.lib.test" to "com.example.lib" (targetPackage leave as is).
Also, make sure that the library is referenced to your test project NOT in Java build path, but as a usual Android library : in Eclipse it must be shown as library in Project->Properties->Android tab, but not in Project->Properties->Java Build Path tab.
Then run you tests.
Per the documentation:
Testing a library module is the same as testing an app.
The main difference is that the library and its dependencies are automatically included as dependencies of the test APK. This means that the test APK includes not only its own code, but also the library's AAR and all its dependencies. Because there is no separate "app under test," the androidTest task installs (and uninstalls) only the test APK.
When merging multiple manifest files, Gradle follows the default priority order and merges the library's manifest into the test APK's main manifest.
NOTE: This solution is based on using Eclipse Indigo (3.8.2) and might have to be implemented slightly differently for another IDE although the basic principles will be the same.
I had similar issues and I found that do the following always works:
(NOTE: These instructions are for building a new project group from scratch. If you have already built parts of the project group, then you may have to modify your projects so that they connect in the same way.)
Create a new Android Library project by checking the "Is Library" checkbox during creation. (for example an Android project named "RemingtonAndroidTools").
Build the Android Library project and verify that it created a jar file in the bin folder. (for example a jar file named "RemingtonAndroidTools.jar".)
Create an empty Android Project for testing the Android app that will serve as an Android Test App. (For example an Android project named "RemingtonAndroidToolsTestApp"). You will not need to modify the source code or resources of the Android Test App project unless you have something that must be added for testing. Many things can be tested without any modifications to the Android Test App Project. The Android Test App project is a bridge between your Android Library project and the Android Junit project that makes testing of the Android Library project via Android Junit possible.
Go the Library tab of Java Build Path for the Android Test App project ("RemingtonAndroidToolsTestApp" in this example).
Add the jar file ("RemingtonAndroidTools.jar" in this example) of the Android Library Project ("RemingtonAndroidTools" in this example) via the "Add Jars..." button.
Create a new Android Test project (for example "RemingtonAndroidToolsTester") that will serve as an Android Library Tester and select the Android Test App project ("RemingtonAndroidToolsTestApp" in this example) as the target.
Go the Library tab of Java Build Path for the Android Library Tester project ("RemingtonAndroidToolsTester" in this example).
Add the jar file ("RemingtonAndroidTools.jar" in this example) of the Android Library Project ("RemingtonAndroidTools" in this example) via the "Add Jars..." button.
Find the last folder of your Android package in the Android Library Tester project ("danny.remington.remington_android_tools_test_app.test" for example) and add a test class ("MainActivityTest" for example) that inherits from ActivityInstrumentationTestCase2.
Edit the test class ("TestActivityTest" in this example) to use the activity (for example "TestActivity") of the Android Test App ("RemingtonAndroidToolsTestApp" in this example) as the parameter for ActivityInstrumentationTestCase2.
Edit the test class ("TestActivityTest" in this example) and create a default constructor that makes a call to super(Class) and passing in the class of the Android Test App ("TestActivity.class" for example).
You should end up with three projects (Android Library, Android Test App, Android Library Tester) that look similar to this:
You should end up with a class for testing your Android Library that looks similar to this:
package danny.remington.remington_android_tools_test_app.test;
import android.test.ActivityInstrumentationTestCase2;
import danny.remington.remington_android_tools_test_app.TestActivity;
/**
*
*/
public class TestActivityTest extends
ActivityInstrumentationTestCase2<TestActivity> {
public TestActivityTest() {
super(TestActivity.class);
}
}
You can then add any test that you want. You will not need to reference the Android Test App ("RemingtonAndroidToolsTestApp" in this example) further to run your tests unless they require access to an Android specific component (like the Assets folder, for example). If you need to access any Android specific components you can do so by modifying the Android Test App ("RemingtonAndroidToolsTestApp" in this example) and then referencing it via the instrumentation provided by the standard Android Junit API. (You can read more about that here: http://developer.android.com/tools/testing/testing_android.html)
If your ulitiy classes do not depend on any android specific code, you can just use standard JUnit unit tests. No need to use the Android versions.

Categories

Resources