I have created a cordova plugin which has an android implementation. This Java code has calls into an SDK that interfaces with specific hardware that the mobile device is connected to. I would like to write unit tests for my Java code and mock all the calls into the SDK so that I can run the tests during CI.
When looking into this, I found the cordova-plugin-test-framework, but from what I can tell, this is for tests that you would write against the javascript code, not the actual platform implementations. I'm sure I could use it and write some tests, but it would require the mobile device to be connected to the hardware, and I don't want to have actual calls into the SDK. In other words, I don't have a way of mocking the SDK calls using this.
I thought maybe I could just run JUnit from the command line with my Java code, but then I was getting errors because it couldn't find org.apache.cordova.CallbackContext. I tried faking my own object, but as I continued, I found more dependencies that my code in isolation just doesn't know about.
Next I figured it would be best to test it within the android project under /platforms in my ionic mobile app, since all the dependencies would be visible at that point. I'm able to run ./gradlew test (https://developer.android.com/studio/test/command-line.html) from here, but I can't figure out how to implement the test cases so that this call will pick them up. Is there some kind of config I can add so it knows where to look for tests? I'd be fine if there was just a certain place I had to put them.
I'm open to any options with this. I just want to be able to run JUnit test as part of our CI process.
Related
I'm working on an SDK that uploads real-time Android test results to a backend. I'd like to be able to attach a test listener to the instrumented tests that run when the connectedAndroidTest gradle command is invoked.
I can annotate the tests with #RunWith and have them use a custom runner with its own listener, but this solution is not ideal, as users implementing this SDK will have to annotate each and every test. We're looking for something that works at a global level.
For unit tests, we can hook into the gradle test API and listen for test results. But, instrumented tests use different gradle APIs, provided by the Android Gradle Plugin (this is where the connectedAndroidTest task comes from). There doesn't seem to be an equivalent gradle-based test listener.
I can set a JUnit test listener via the testInstrumentationRunner in build.gradle - but this listener runs on the Android device under test - I'm looking for something that can listen to test results on the local machine, rather than the Android device.
Android Studio seems to have this capability - when running Instrumented Tests via a run configuration, the IDE can report on instrumented test results in real-time. I've had a dig around in the source code, but it's not clear to me how this works.
Any help would be greatly appreciated!
I've done some Cordova plugins and I would like to write unit tests on it. The idea is that, after I run cordova build android, for example, the test files would be moved to the correct folder on Android and I could run tests with Java. Is that possible?
I've seen some plugins to make possible to test a Cordova plugin, like cordova plugin test framework. The problem here is that it only tests the call and the callback. It's not possible to mock objects, for example. For instance, I have a plugin to track GPS and I would like to test it.
I also would like to test the iOS side as well.
You were right in your research that the current tests for the Cordova Core plugins are all using cordova-plugin-test-framework to implement tests that are run on the device with e.g. cordova-paramedic or cordova-mobile-spec (see the CI configuration in the GitHub repositories on how to trigger a build with cordova-paramedic for example).
The only Cordova projects where "normal" unit tests, written in Java for Android and Obj-C for iOS, are used are the platforms. For Android for example this folder exists: https://github.com/apache/cordova-android/tree/master/test These tests can be run via run_java_unit_tests.js, which is also available via npm as npm run java-unit-tests.
I am pretty sure the same concept could be applied to plugin tests.
(Please let me know if you try and this actually works!)
I tried to look around about how to launch an automated test in multiple devices, but I couldn't really find what I was looking for.
I have like 5 tests per class and I want to execute just one test in all my connected devices, like a End to End test to login.
I tried to use connected device but it doesn't launch only the test I want...
I'm using Espresso, UIAutomator, Gradle and AndroidStudio.
How can I run that single test in my devices using these tools?
Use gradle connectedCheck command
You can find an example app here from google
https://github.com/googlesamples/android-testing-templates/tree/master/AndroidTestingBlueprint
There you can also read how to run the example tests on multiple devices from the command line / terminal, or from within Android Studio
You can also take a look at Spoon if you want to use an external tool plugin:
https://github.com/square/spoon
good luck
Why do you need to have an emulator or device plugged in for the testing to take place? Why can't I just generate coverage for my tests without the use of these?
It all depends on your Unit-Test.
If you're testing classes that dont use at all the Android Framework, and only the standard Java classes, then you could run the Unit test and get a code coverage (althouhg I don't have a step by step procedure to give you).
But if you're using any part of the Android Framework (that is, any class in an android.* or com.android.* package), then you'll need to run in a DalvikVM, meaning an Android emulator.
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.