Trying to understand android testing - android

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.

Related

Generate unit tests on Android

Colleagues,
I am having hard time to find a library/framework/etc... which could help me to generate unit tests in Android.
I know that in Java there are multiple solutions, which could generate unit tests based on the source code. Are you using anything like this for Android?
(My project if fully written in Java).
Use just JUNIT - this should help :
https://developer.android.com/training/testing/unit-testing/local-unit-tests
Use Unit Test Architect
I am in the same boat as you were/are. Although TDD should be the approach for writing tests, but there may be a lot of untested code already written many times in larger projects.
One day I got frustrated with writing test cases of existing, older codebase. Hence, I thought of auto generating all the unit test cases.
I have created an Open-source Gradle Plugin which can be used for the above task. It is already hosted on mavenCentral. I have used it to generate test cases for my projects. But it can be used in any gradle project, (android, java, kotlin, kotlin+java). It may be rough around the edges but it has done it's job well for me.
BuildScript Dependency:
classpath "io.github.orange-3:unit-test-architect:$PLUGIN_VERSION"

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.

Robolectric Installation

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.

Unit testing Android application logic

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.

Android JUnit4 testing

I want to run some JUnit4 tests. The code relies on some Android libraries(Android XML parser), but does not create any activites and so on. When I try to run tests I got that an Android class that I need was not found. Is there any way to run JUnit4 tests with Android code, not to test activity but to test code with some libraries.
I had the same problem and tried to adapt JUnit4 to Android's existing TestRunner - without success. Therefore I created a new project called JUnit4Android. It's a TestRunner application library for JUnit4 and JUnit3 tests and test suites. So you can run your existing JUnit4 tests with it. Please find more information on GitHub:
https://github.com/dthommes/JUnit4Android/wiki
There is no way (that I'm aware of) to use JUnit4 on Android. It does support JUnit3 though, if that's an option for you?
Alternatively, you could use Robolectric and run your tests on your development machine (where you'll be able to use whichever unit test framework you like). Whether this will work for you depends on exactly what you're testing, but it might be worth a go?
It might be little bit late, but there's finally an official update from Google about junit4:
based on Android-test-kit project and some other sources it's clear that:
The AndroidJUnitRunner is a new unbundled test runner for Android, which is part of the
Android Support Test Library and can be downloaded via the Android
Support Repository. The new runner contains all improvements of
GoogleInstrumentationTestRunner and adds more features:
- JUnit4 support
- Instrumentation Registry for accessing Instrumentation, Context and Bundle Arguments
- Test Filters #SdkSupress and #RequiresDevice
- Test timeouts
- Sharding of tests
- RunListener support to hook into the test run lifecycle
- Activity monitoring mechanism ActivityLifecycleMonitorRegistry
Actually, it's already presented in Support Repository. If You go to
%ANDROID_HOME%\extras\android\m2repository\com\android\support\test\testing-support-lib\
it's possible to find testing-support-lib in there (aar, jars etc.) which allows to use JUnit4. Even more, it contains espresso library same location which is handy for UI testing. Seems Android sites and support lib official references will be updated soon with that info.

Categories

Resources