Does Kotest (previously KotlinTest) still work in Android Studio? - android

As far as I can tell, Kotest requires JUnit 5:
https://github.com/kotest/kotest/issues/1104
It also requires Gradle 6:
https://github.com/kotest/kotest/issues/1301
I presume it's possible to get this all set up and working, but isn't it true that JUnit 5 and Gradle 6 are not really supported for Android development? I'm concerned that, even I get this all working now, I may have problems down the line.

Kotest does work on Android Studio.
JVM tests
To setup the JUnit 5 runner for your unit tests (plain JVM) you can follow the instructions at https://kotest.io/quick_start/.
Of course If you have an already started project with JVM JUnit4 tests you will have to make additional steps to configure both the runners for the JUnit4 and for the new JUnit5/Kotest tests, but it is outside of the scope of this answer.
Android Robolectric tests
You can find the instructions on how to set it up here. Given Robolectric ones are plain JVM tests and not instrumented ones, you can use the JUnit5 runner and they will run just fine.
Android instrumented tests
Apparently Kotest has a JUnit4 runner project too, but no instructions yet on how to set it up with Android.

Related

How to connect android studio testing GUI to gradle task?

There are some tests in my android project and configured CI
Before deploying tests are launched using gradle wrapper(4.10.3)
95% of tests are robolectric tests
And there are cases when these tests are not passing because of different reasons, but the problem is that when i run them from android studio GUI tests are working fine(passing).
For example i use mockito for mocking and mock-maker-inline, i have this MockMaker in core module that is used in all other modules, if i launch tests from android studio - they are passing, if i launch using gradle wrapper - they are all failing. It can be solved by adding MockMaker in module, where i have tests, but still why it is working from android studio, but not working from console?
My test running options:
Case when i remove mock maker from locations module(dependent on core module with enabled mock-maker)
All tests are filing with this error
But when i run with android studio tests are passing and everything is fine.
What is the difference between these two launches?(default launch type from android studio and gradlew testDebug).
And is there a way to connect my custom gradle test task with android studio tests gui?
The biggest difference between the GUI and running from terminal is that the Gradle wrapper will execute the tests of different modules concurrently if you have it enabled in gradle.properties:
org.gradle.parallel=true
If you have tests in different modules acting upon the same singleton, or the same mocks, then you can run into any number of conflicts.

Porting JUnit tests to Android Testing Framework

I'm planning to port my JUnit tests to Android Testing framework.
Some of the tests only involve the JVM but not the Android system, is it still necessary to port them? Android is using Dalvik and will replace it with ART(Android Runtime) in Lollipop, both of which are different from the JVM (Please correct if I'm wrong.). In this sense, it seems necessary to port all the JUnit tests to the Android Testing framework.
However, some tutorial argues that
"If possible, you should prefer to run your unit tests directly on the
JVM as the test execution is much faster compared to the time required
to deploy and run the test on an Android device."
http://www.vogella.com/tutorials/AndroidTesting/article.html#androidtesting
I'm not an expert on JVM, Dalvik nor ART. Can someone clarify this issue? Is it necessary to port the tests that only involve JVM to Android Testing Framework?
Thanks!
This depends on what you would like to test and the environment in which you run your tests in.
In theory, pure non-Android-specific Java code (aka. POJOs) you write will work on whatever virtual machine you run it on--JVM, Dalvik, or ART.
If you agree with that theory, then if you are already running your tests on a JVM, there is no need to run it on Dalvik or ART, especially if you consider the speed at which JVM will execute the tests. (Running it on Dalvik involves building the apk, and installing it, and running an adb shell command which can take some time...)
Of course, if you feel that the behavior of your Java code may change depending on the runtime, then you should probably port those tests over to your Android tests.
Recently, I checked out Android Testing Support provided in Android SDK.
As far as I know, you can write Unit Tests, which can be executed directly on JVM in your computer or CI Server (e.g. Jenkins) without Android device or emulator. The only requirement is the fact that these tests and code, which is tested have to be written in pure Java without any dependencies to Android SDK and Android Context. These tests have to be located at src/test/java directory. You can switch test artifact in Build Variants in Android Studio to "Unit Tests" and run your tests with IDE. you can also run them via Gradle wrapper with the command: ./gradlew test
If your tests or code, which is going to be tested depend on Android SDK and Android Context, you should use Android Instrumentation tests, which have to be located in src/androidTest/java directory. These tests have to be executed on Android device or emulator. You can switch test artifact in Android Studio to "Android Instrumentation Tests" and run your tests with IDE or use Gradle wrapper command ./gradlew connectedCheck
You can check official article about Unit Testing at: http://tools.android.com/tech-docs/unit-testing-support . It's worth reading. It's a bit outdated, because now you can use build tools: 1.1.0 instead of 1.1.0-rc1, but rest of the information is up to date. After reading this article, you should understand this topic better.

Run robolectric and android unit test from Android studio

I currently have various AndroidTestCases which use Mockito and the module dexmaker-mockito. I am now trying to add Robolectric test cases using the robolectric plugin.
I have everything running fine except that when I try to mock methods with no arguements I get an IllegalArgumentException from Dexmaker. Removing the dexmaker-mockito dependency and using mockito version 1.9.0 instead of 1.9.5 causes the error to go away but causes all of my AndroidTestCases to fail. Is there anyway in gradle to have dexmaker-mockito exclude from my robolectric test cases? Or does anyone know of any other way to run both android unit test and robolectric unit test from android studio?
Error:
java.lang.IllegalArgumentException at com.google.dexmaker.mockito.InvocationHandlerAdapter.invoke
Update
I tried gradle-android-test-plugin and robolectric-gradle-plugin but was unable to to get rid of the IllegalArguementException without changing the version of mockitio to 1.9.0 and removing dexmaker, dexmaker-mockito from my dependencies.
I tried the guide but was unable to get Android Studio to recognize my source directories without adding them to main or test source sets which break my build because robolectric is not compiled for those gradle tasks and I do not want it to be.
I ended up following the guide here this time the error disappeared when I ran the tests from command line but persisted when running from android studio which I found odd. Again changing the version of mockitio to 1.9.0 and removing dexmaker, dexmaker-mockito from my dependencies in my Android App removed the error. For now I will settle for not being able to run the unit tests from android studio until I find a better answer.
If I understand correctly what dexmaker-mockito is supposed to do, it's meant to be used with Android Unit Tests that run on device, so it's good for your Android Test Cases.
Robolectric tests run on the JVM and should be run as JUnit test, not Android tests. They should not be using dexmaker-mockito as they never get deployed to device, they can just use the normal Mockito libraries, with scope set to test.
I think you may not be able to mix the two, you may have two keep your robo tests separate from your Android unit tests.

Best way to run fast JUnit tests in Android project in Android Studio

I have some plain old Java classes and simple JUnit tests in my Android Studio project. They currently live inside my Android Module. If I run them as Android tests they pass fine, but they're really slow as it requires launching or connecting to the emulator.
If I try to run one as a JUnit test, I hit the !!! JUnit version 3.8 or later expected JUnit version problem. This answer explains how to workaround that issue. Unfortunately, I then hit the java.lang.NoClassDefFoundError: junit/textui/ResultPrinter, which I can't figure out how to fix.
I then tried to move my JUnit tests into a separate Java module that depends on the Android Module. Everything compiles fine. I added a new configuration to launch the JUnit tests (:MyJUnitTests:test), but the tests fail with package com.myproject.util does not exist. It looks like maybe the classpath isn't including the classes from the dependent Android Module.
Does anybody know how to fix this classpath issue? I've looked at lots of related answers and none of them seem to work for me. Or is it a just a bad idea to try and keep my JUnit tests in their own Module?
I can get the JUnit tests to run fast and pass if I move my plain Java classes and their JUnit tests into a completely separate Module (e.g. here), and reverse the dependency so the Android Module depends on the Java Module. Is that the preferred solution?
The basic problem is that Android Framework classes don't work well outside the context of Android OS, so any code that has dependencies on Framework classes doesn't run in a regular JUnit environment, as you've found.
Your solution of trying to move the JUnit tests into a separate module won't work because you can't have a plain Java module depend on an Android module. Android Gradle modules don't act like Java modules, because Android builds are much more complex, and because the end result of an Android module build will be an APK or an AAR, which other module types won't understand.
If you can move your plain Java classes and unit tests into a plain Java module and have the Android modules depend on that, it will be the best approach that will get the most support from official features in the IDE. It will also have an architectural benefit in that it will keep those classes free from Android abstractions, making it more portable, and enforcing a separation of business logic from UI or storage or other things more device-specific.
If that's difficult for you to do, then a lot of developers in your shoes go with Robolectric, which is a test harness allowing code depending on many parts of the Android Framework to run in a JUnit environment without an emulator or device. It's not officially supported by Google, but Google is aware that it's widely used and tries hard to not wantonly break it.

Best way to run Robolectric tests on Android device

I have a Robolectric test project setup, but I'd like to also run these tests on my device to check that I don't get bit by JVM vs Dalvik implementation differences.
Unlike robolectric tests, I won't run these tests frequently. My concern is that there's little effort to maintain the test suite and that they verify actual device functionality.
What's the best way to do that?
What I've currently got:
My robolectric test project as a test case TestPackage. I created an Android Test project with a test case TestRoboOnAndroid. It creates a TestPackage and has a test for each test in TestPackage.
Right now, every time I add a test to my robolectric suite, I need to manually add it to my device suite. Is there some way to do that automatically with reflection?
Also, Robolectric uses JUnit 4 (by default) and Android uses JUnit 3. So I have to write all of my Robolectric tests using JUnit 3 style (importing from junit.framework instead of org.junit).
The whole point of Robolectric is NOT to run it on the device and the design is based on that. If you want to run something on the device look at the default instrumentation tests from the SDK or Robotium.
It is totally feasible to run your Robolectric tests on the JVM and in addition create Robotium tests that rely on device specific interaction (e.g. creating screenshots, hardware differences...) and run on devices and emulators all combined into one build.
The easiest way to do that is to use the Android Maven Plugin.
I use a tiered system, where I prefer earlier tiers where possible:
Pure unit tests. I try to make as much code as possible fully independent of Android APIs, and then use "pure" unit tests which can run on any JVM. These tests are the fastest, and it helps keep code that has no need to be Android-specific portable.
Robolectric-supported unit tests. Where my code has only small dependencies on Android APIs, that can be satisfied by Robolectric shadows, I test it with Robolectric. There is a little more setup time for Robolectric compared to pure tests, but it's still faster than starting/running on an emulator.
Android framework tests. Where Robolectric doesn't cut it - either because the shadows don't exist, or because I'm heavily using Android APIs (and therefore want to test against the Real Thing) - I write test that run on the emulator/device with the default framework.
The point of the tiers is to keep things as simple as possible, which keeps the full suite faster and helps promote cleaner code.
We use Robolectric for unit testing against the JVM and Calabash-Android for system testing against Dalvik. Both can be integrated into our Jenkins CI build and between the two tools I feel that we cover all the bases.

Categories

Resources