13

I'm hoping that this is just something I'm doing wrong here. I'm trying to use Dagger 2.0 to inject dependencies for my JUnit tests (not Espresso tests, just pure JUnit). So, I have a 'main' java module and a 'test' java module. In the main module, I've got a Dagger Module and a Component:

@Module
public class MainModule {
    @Provides
    public Widget provideWidget() {
        return new ConcreteWidget();
    }
}

...

@Component (modules = MainModule.class)
public interface MainComponent {
    void inject(WidgetConsumer consumer);
}

And in my test module, I have the following:

@Module
public class TestModule {
    @Provides public Widget provideWidget() {
        return new Widget() {
            @Override
            public void doThing() {
                int y = 6;
                y ++;
            }
        };
    }
}

...

@Component(modules = TestModule.class)
public interface TestComponent extends MainComponent{
}

My build.gradle has dependencies that look like this:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'
    testCompile 'junit:junit:4.12'

    compile 'com.google.dagger:dagger:2.9'
    testCompile 'com.google.dagger:dagger:2.9'

    annotationProcessor 'com.google.dagger:dagger-compiler:2.9'
    testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.9'
}

For whatever reason, Dagger generates DaggerMainComponent, but refuses to generate DaggerTestComponent. There appear to be no errors in the gradle output when I build.

Here's the thing... I think the annotation processor is running, but somehow the android gradle plugin is failing to pull in those generated sources during compile-time. I have inspected the app/build/generated/source/apt/test/ directory and found DaggerTestComponent.java in there, but for some reason, it's not imported as a dependency.

Any thoughts? Here is a link to a test project showing my issue

azizbekian
  • 60,783
  • 13
  • 169
  • 249
Alex
  • 1,103
  • 1
  • 11
  • 24

3 Answers3

20

Add this to build.gradle after android DSL:

android {
    ...
}

android.applicationVariants.all {
    def aptOutputDir = new File(buildDir, "generated/source/apt/${it.unitTestVariant.dirName}")
    it.unitTestVariant.addJavaSourceFoldersToModel(aptOutputDir)
}

Thereafter, your test component would be recognized.

For Kotlin replace generated/source/apt/... with generated/source/kapt/...

There is an issue raised in the tracker concerning this.

azizbekian
  • 60,783
  • 13
  • 169
  • 249
  • Thanks for the workaround, but I'm having trouble with it. Is there anywhere I can examine the DSL syntax? It's telling me that `applicationVariants` doesn't exist in android. I have a feeling they either renamed it, got rid of it, or moved it somewhere else. `android.buildTypes` and `android.sourceSets` exists, but `android.applicationVariants` doesn't seem to (with gradle plugin v 2.3.0-rc1). – Alex Mar 14 '17 at 21:09
  • I've just made one change in the source code you provided. I've only added those three lines after `android {}` in `build.gradle`. Check it out. – azizbekian Mar 14 '17 at 21:13
  • Yeah, I tried exactly that (after the android block). I get "Could not get unknown property 'applicationVariants' for object of type com.android.build.gradle.LibraryExtension." Ah! I think I know what my issue is... I'm using `apply plugin: 'com.android.library'` at the top. Sorry, I posted an example project here and am trying to apply this fix to my actual project, which is an android library (AAR) project. I bet libraries don't have variants or something. How would this look for a library project, do you know? – Alex Mar 14 '17 at 21:16
  • 2
    Nevermind, it's `libraryVariants`. Figured it out. Tested your fix and it works perfectly, thanks! Can't wait until Google fixes their plugin though, we really shouldn't have to do this... – Alex Mar 14 '17 at 21:21
  • I was recking my brain with this for last few hours. Finally found workaround that works. Thanks! – Micer Mar 21 '17 at 16:16
  • Any idea how to do this in the pure Java / Intellij Idea case? If so please see https://stackoverflow.com/questions/57759253/how-do-you-define-dagger-components-and-modules-in-tests. Thanks! – Ewan Sep 02 '19 at 15:44
5

I found a workaround, just in case anybody gets stuck with this issue in the future. It appears the testAnnotationProcessor command in the android gradle plugin does not work for test modules (possibly a bug in their implementation?). So you can write testAnnotationProcessor and your build.gradle will compile but it seems to not work properly.

The workaround is to fall back to the older third-party annotation processing plugin by Hugo Visser (android-apt).

To do that, add the following to your buildscript dependencies in your main build.gradle:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0-rc1'

        // ADD THIS LINE HERE vvv
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

Then, in your individual module's build.gradle, add the following line at the top:

apply plugin: 'com.android.library'

// ADD THIS LINE HERE vvv
apply plugin: 'com.neenbedankt.android-apt'

Finally, instead of using testAnnotationProcessor and annotationProcessor, just use apt and testApt:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'

    compile 'com.google.dagger:dagger:2.9'
    // USE apt INSTEAD OF annotationProcessor HERE vvv
    apt 'com.google.dagger:dagger-compiler:2.9'

    testCompile 'com.google.dagger:dagger:2.9'
    // USE testApt INSTEAD OF testAnnotationProcessor HERE vvv
    testApt 'com.google.dagger:dagger-compiler:2.9'

    testCompile 'junit:junit:4.12'
}

Note that you must use the 1.8 version of android-apt, as the 1.4 version does not ship with the testApt command/function/whatever.

Alex
  • 1,103
  • 1
  • 11
  • 24
  • 2
    It seems that it doesn't work anymore (working with Gradle 3.1.0) --> Error:android-apt plugin is incompatible with the Android Gradle plugin. Please use 'annotationProcessor' configuration instead. – Cesar Castro Mar 30 '18 at 18:26
2

Depending on your test type:

  • insert testAnnotationProcessor "com.google.dagger:dagger-compiler:2.x" inside dependencies on your build.gradle file for src/test

or

  • insert androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.x" inside dependencies on your build.gradle file for src/androidTest
Fraudlic
  • 66
  • 5