I am using Robolectric and the "android-unit-test" plugin in my android project. I have multiple modules (eg foo and bar) and would like to use the same test runner across all the modules. To achieve this I created a Test module to hold my test runner and any custom shadow classes. In foo's build.gradle I have testCompile project (":main:Test")however android studio will not import my runner unless I also include androidTestCompile (":main:test"). Furthermore, when I run ./gradlew test from the command line I get various errors saying that my test runner and shadow classes cannot be found. Anyone have any advice?
With your given information I guess you missed one little aspect: test classes appear not in jars.
When your shared TestRunner is under src/test/java then other modules will not see it. When I'm correct then place you TestRunner at src/main/java and all modules should have access to our support classes.
Here is also an example where i did the same https://github.com/nenick/AndroidAppDevelopment
Related
I have the following Project Structure:
Main App
--app
--featureModule1
--featureModule2
--TestKit(Library module)
where Testkit has all dependencies including app and featureModules. The Testkit included all the unit tests related to the features in app and featuremodules.
When i run unit tests from Android studio(Right click-> Run Test in Testkit), they run fine. However whenever i try running it from gradle command: ./gradlew TestKit:testInternalDebugUnitTest, it throws NoClassDefFoundError for all the dependencies of other modules(for both app and feature modules).
Also i have already added implementation and testImplementation dependencies of all the modules in test module.
Please suggest:
Do i need to add path of classes generated in other modules, if yes pls guide where.
Also running Test with Coverage fails with
java.lang.VerifyError: Bad return type
Please suggest what am i doing wrong here.
Note:
I have created a Testkit because of the multiple open issues of Roboelectric in feature modules for ex: https://github.com/robolectric/robolectric/issues/5428
Versions
AS: 4.0.1
gradle: 4.0.1
gradle-wrapper: 6.5
Robolectric: 4.3.1
I was able to solve the problem using the following runtime test dependencies:
testRuntimeOnly(files("${projectDir}/../app/build/intermediates/app_classes/internalDebug/classes.jar"))
testRuntimeOnly(files("${projectDir}/../featureModule1/build/intermediates/app_classes/internalDebug/classes.jar"))
testRuntimeOnly(files("${projectDir}/../featureModule2/build/intermediates/app_classes/internalDebug/classes.jar"))
inside build.gradle of Testkit.
Can refer to the following link for more details:https://github.com/android/app-bundle-samples/issues/11#issuecomment-675725610
I have a Gradle project containing the two modules app and test, where test contains utilities for testing only. Now I'd like to setup this module, so it doesn't include any outputs into the main configuration of app; even not accidentally.
implementation project(':test') # should fail or not contain any inputs
testImplementation project(':test') # should include all inputs
androidTestImplementation project(':test') # should include all inputs
How do I configure test to behave like this?
I'd assume it would be similarly to how the Android plugin handles configurations for build types and flavors, but I'm also not sure on how to figure this out.
I think these are handled with Gradle consumer attributes. Maybe there's a filter or an attribute which could be applied to it to make it only available to tests.
You could use annotations for that:
https://developer.android.com/studio/write/annotations#visible
Another way would be exclude testing code to new module named as sub_test and use testImplementation or androidTestImplementation of that sub_test module in your test module
Found: Use separate test modules for instrumented tests, which tells the how to do it:
... apply the com.android.test plugin instead of com.android.library.
The java-test-fixtures plugin almost behaves like I wished, just a bit more verbose.
implementation project(':test') # should fail or not contain any inputs
testImplementation testFixtures(project(':test'))
androidTestImplementation testFixtures(project(':test'))
Some other downsides for now
As Tom Tresansky Is the java-test-fixtures plugin incompatible with the Build and run using IntelliJ IDEA setting? asked and answered, the Android Studio doesn't handle the testFixtures source set well.
Also it is not yet available for Kotlin or Android. But as Michael Evans pointed out, there's tasks already open for Android and on YouTrack.
But creating the test fixtures with a Kotlin JVM project and consuming these with an Android project works fine for me.
I am writing junit tests on android project using the new unit test support http://tools.android.com/tech-docs/unit-testing-support.
While the unit tests run on the 'com.android.application' module perfectly but they always fail on the 'com.android.library' modules. This has not been documented in http://tools.android.com/tech-docs/unit-testing-support . So I wonder whether I am the culprit.
When I write those tests on library modules, the tests can not find the classes on the module and always gives following errors:
package does not exist
error: cannot find symbol
The android unit test support is in experimental phase right now, but is there a solution to it.
UPDATE
I have added this issue to android issue tracker https://code.google.com/p/android/issues/detail?id=161038
It looks like the task to compile the unit tests doesn't depend on the task to compile the library code.
The following fixed it for me:
afterEvaluate {
tasks['assembleDebugUnitTest'].dependsOn(tasks['assembleDebug'])
}
I run the tests using
./gradlew testDebug
If you don't want to modify your build.gradle, manually specify the assembleDebug task on the command line should also do the trick:
./gradlew assembleDebug testDebug
In my android library project I also failed to get the tests running. What I did was create a test application that uses the library and wrote tests in the application that call the library methods.
This might not be the ideal solution, but was the way we got this to work.
Have a look over here https://github.com/nenick/AndroidStudioAndRobolectric
There you can run unit tests on libraries and flavors. And no you don't need to use Robolectric as Gaurav Vashisth stated. You can if you want to.
Here is an example of JUnit test in a library module
I have an Android Gradle 1.1 Project with several Modules that have some dependency on the others.
Project
├ Module2
│ ├ src/main: imports classes from Module1
│ └ src/test: imports classes from Module1, tests Module2/src/main
└ Module1
├ src/main: implements classes needed by Module2/src/main & Module2/src/test
└ src/test: tests Module1/src/main
My Modules themselves compile fine.
My question is related to testing the modules.
(FYI: I am using Robolectric)
I have seen several "similar" questions related to Android build & test dependencies, but none of the ones that I have found seem to be asking what I am looking for:
Android Gradle 1.1 - adding a test dependency on another project's tests
How to run unit tests with dependency to an Android library module?
Gradle Android unit tests that depend on an 'aar'
Multi-project test dependencies with gradle
Jacoco and Unit Tests Code Coverage with android-gradle-plugin >= 1.1
Android Studio module that depends on another module's tests
These questions are also either old, not focused on using Android Gradle 1.1+ built in Unit Test abilities, or not really that relevant.
What I am asking is: "How can a [java compiled?] unit test import another android module (normally a .aar file) in the same project?"
A "testCompile project(':module1')" doesn't seem to do the trick.
I suspect that I want to either:
Compile the other module that I depend on as a .jar file
Use the other module's already compiled .class files
Extract the .class files from the other module's .aar file
Find some other built in way to do this
Is there a slick way to do this built in to the Android/Gradle build process?
Am I missing something obvious here?
Thanks!
Pv
The secret is to have project.properties and test-project.properties file next to your AndroidManifest.xml
At the test-project.properties insert all your exploded aar resource path (e.g. android.library.reference.3=../../build/intermediates/exploded-aar/AndroidStudioAndRobolectric/core/unspecified)
I explain this a bit more at http://nenick-android.blogspot.de/2015/02/android-studio-110-beta-4-and.html And a ready to use example can be found at https://github.com/nenick/AndroidStudioAndRobolectric/tree/library
If your module under test is depending on pure Java/non-Android code, an alternative approach is to extract out a new java-library module (one that builds a .jar rather than an .aar) and depend on that. Unit tests can run fine in this case.
(Probably not so helpful for the original poster since they are using Robolectric but still)
A new AndroidStudio 1.1 version introduced the unit testing support. This URL http://tools.android.com/tech-docs/unit-testing-support provides step-by-step instruction how to setup IDE to run JUnit tests for Android sources.
This plugin https://bitbucket.org/hvisser/android-apt used to provide Dagger2 generated files to AS and it works OK for usual Android code but unfortunately there is no generated Dagger2 files for any JUnit test class. I tried to configure dependency like
androidTestApt 'com.google.dagger:dagger-compiler:2.0-SNAPSHOT'
according to android-apt plugin documentation but without success.
I think the problem is in different sources directory for Unit tests - it's src/test/java instead of src/androidTest/java that used by android instrumentation tests.
Can you please provide any help or info how to resolve this trouble?
Having
// You version may vary
androidTestApt 'com.google.dagger:dagger-compiler:2.0-SNAPSHOT'
in your dependencies, open a terminal in your project, run
./gradlew assembleTest
This will generate the Dagger component classes living under your androidTest source set.
Go back to Android Studio, the class now exists and can be used.