I am attempting to write instrumentation tests for an app that uses Dagger2. The app has several build types and one of them is called automation. The automation build type is also set as the testBuildType in the build.gradle.
The activity I'd like to test has a Presenter injected that depends on a Repository. What I'd like to do is inject a real repository when I'm building any build type except for automation and then when I build the automation build variant I'd like to inject a mock Repository.
In my androidTest source set I've created a MockComponent and a MockModule which create mock a mock version of the Repository. What I figured I would be able to do is build an instance of MockComponent and use it to provide a Mock Repository. The problem seems to be that if MockComponent and MockModule are in the androidTest source set then Dagger never generates the DaggerMockComponent class when I build. If I move MockComponent and MockModule to the automation source set then Dagger does generate the classes however then I'm in a position where I want to add an inject method to MockComponent so that I can inject an object into my activity test class but MockComponent can't get see the activity test class because it's in the android source set.
Any ideas why Dagger won't generate the DaggerMockComponent class when it's in the androidTest source set?
The issue ended up being that in my build.gradle file I needed to include a dependency for the androidTest source set. Normally you use
androidTestCompile "com.package.version:1.2.3"
But for dagger you have to use apt so the line looks like:
androidTestApt "com.google.dagger:dagger-compiler:$rootProject.ext.daggerVersion"
The really confusing thing about this was that since I am using a build type (automation) for my testBuildType I was able to add dagger code to the automation source set and dagger could compile it b/c it wasn't in the androidTest source set. Then I tried to add the dagger code to the androidTest source set and suddenly it was like it was invisible to the dagger compiler b/c it would never generate the dagger classes for the components that were specified in the androidTest source set.
Related
I have a android project with multiple modules, module B that depends on module A
dependencies {
implementation project(':features:A')
}
I want unit test in module B to extend base test from module A. An IDE resolved all dependencies successfully, but in build time only production code from module A is accessable in test.
I tried to add dependency specificly for tests:
dependencies {
testCompile project(':features:A').sourceSets.test.output
}
This results an error:
Could not get unknown property 'test' for SourceSet container of type org.gradle.api.internal.tasks.DefaultSourceSetContainer.
Same if I'm trying to create custom artifact with tests.
How can I get access to test-specific code in base module from dependent module?
AS 3.1, gradle 4.1
The best solution I found is to create third module just for tests, put my base test classes and test dependencies there.
And use it in both module A and module B (and all other modules - just one module for all unit test dependencies)
testImplementation project(':features:basetests')
Disadvantage - it is possible to import it in non-test artifacts (e.q. implementation project(':features:basetests')). Good code review can protect from such mistakes.
Looks like there is no convenient way to define base shared test-only code.
In our Android app we're using DBFlow to access the SQLite database. We're referencing the classes generated by DBFlow via Kotlin. We are already aware of the fact that we have the model classes as well as the database class in Java as code generation won't work when writing these classes in Kotlin.
However we still have to build the code twice after every project clean. Executing the first build on a device results in ClassNotFoundExceptions for seemingly random Kotlin classes (even if they don't access code generated by DBFlow or any of the model classes defined by us). The same is reported already at compile time when enabling Proguard which of course fails the build. The second build always succeeds.
The funny thing is, that code generation already works at the first run - the classes are there and are also picked up by the IDE. But the compiler somehow can't find them making me think that the code generation happens too late in the build process. On the other hand as explained above there are also classes not found which don't have to do anything with code generation and/or annotation processing.
So is there a better solution to this problem than a second build?
For reference, the relevant parts of our app's build.gradle looks like this - just like the DBFlow documentation is suggesting:
def dbflow_version = "3.0.0-beta4"
dependencies {
kapt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}"
compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}"
compile "com.github.Raizlabs.DBFlow:dbflow:${dbflow_version}"
}
kapt {
generateStubs = true
}
Edit: I found that I also have to rebuild twice for every change I make to the code. It compiles correctly in the first build if I didn't clean before, but the changes simply aren't picked up.
If you use kotlin and retrolambda this might fix it:
me.tatarka:gradle-retrolambda:3.4.0
github gist
I am migrating a quite big and complex legacy project to Gradle.
I have many libraries projects, where each project has its own test subprojects.
The project structure looks as follows:
- LibraryX
-- LibraryXTestsOne
-- LibraryXTestsTwo
- LibraryY
-- LibraryYTests
....
Each library is configured as follows:
The main sourceset contains all the library code
The androidTest sourceset is empty
Each test project is configured as follows:
It lists the parent library as a dependency
The main sourceset is empty
The androidTest sourceset contains all the tests code
With such a configuration I manage to run the test with :libraryTestsA:connectedAndroidTest, but I can't get the test coverage to work. I enable it through
buildTypes{
debug{ testCoverageEnabled true }
}
Apparently the classes of the parent library are not instrumented causing the code coverage to be zero.
Any suggestions?
It turns out that you just need to set testCoverageEnabled to true for all the projects/libraries that the test project depends on.
That will be enough to instrument your code.
You still need to create a custom jacocoReport task though, since the one provided by the android plugin looks up classes and sources in the project main sourceset, which are empty in a configuration like mine.
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.
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