Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gradle testAnnotationProcessor for classes under test #164

Closed
Travisnv opened this issue Nov 17, 2021 · 14 comments
Closed

Gradle testAnnotationProcessor for classes under test #164

Travisnv opened this issue Nov 17, 2021 · 14 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@Travisnv
Copy link

Hi,

This is more than a question than a defect. I trying to use dinject for classes under test source set with gradle. For an example:

/src/test/java/

@singleton
public class Client {

}
...
...
@CustomScope
public class Client2 {

}

on build.gradle

I have setup the following:

dependencies {
...
testImplementation group: 'io.avaje', name: 'avaje-inject', version:'6.11'
testAnnotationProcessor group: 'io.avaje', name: 'avaje-inject-generator', version:'6.11'
...
}

on the IDE itself, I see IntelliJ can find generated class from import statement. However, when I issue Gradle task clean compileJavaTest test I see gradle complains about not about to find the generated classes from dinject.

Can you please have a look and have any direction for using dinject for test source set ?

Thanks and Regards,
Travis

@rbygrave
Copy link
Contributor

Hmmm, the above looks ok to me. Do you want to create a little example project? I can then clone it and look.

@Travisnv
Copy link
Author

Please have a look at: https://github.com/Travisnv/dinject-test-source-set.git

From src/test/java/test I have two client class:

If I use default scope (@singleton), compile task work fine. However, if I use custom scope (@TestScope) for client classes, I see following error:

error: Failed to create module filer Attempt to recreate a file for type test.TestModule
error: Failed to create module filer Attempt to recreate a file for type test.TestModule

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileTestJava'.

@rbygrave
Copy link
Contributor

rbygrave commented Nov 23, 2021 via email

@rbygrave
Copy link
Contributor

rbygrave commented Nov 23, 2021 via email

@Travisnv
Copy link
Author

Travisnv commented Nov 23, 2021

I have a look and see we want to archive similar objective: a scope during test. However, rather than having a common test scope, I would like to build scope for every single test of a test suite.

Let's say we have a suite with different test classes. Assuming one test class only have 1 test method with 2 events: test starts and test finishes. I want to construct scope per test. Here is an example for two tests:

Test 1:

  • create test scope
    • At test starts
    • At test finishes
  • close test scope

Test 2:

  • create test scope
    • At test starts
    • At test finishes
  • close test scope
    ...
    ...
    repeat for the rest of tests of suite

I hook those events by calling scope constructor and scope close on a test listener (a testng specific stuff).

@rbygrave
Copy link
Contributor

rbygrave commented Nov 23, 2021 via email

@Travisnv
Copy link
Author

Thanks, I did just exactly what you have in sample test class, it works. Can we back a original question: compileTestJava goal when we have:

1.custom scope interface
2. classes which is annotated with custom scope

under /src/test/java.

I have a few try moving both classes from /src/test/java to /src/main/java. At this time, both compileJava and compileJavaTest finish without any error.

@rbygrave
Copy link
Contributor

rbygrave commented Nov 24, 2021 via email

@rbygrave
Copy link
Contributor

It is not compiling, gives a NPE during compile

./gradlew --stacktrace clean test
...
Caused by: java.lang.NullPointerException
        at io.avaje.inject.generator.SimpleModuleWriter.createFileWriter(SimpleModuleWriter.java:238)
        at io.avaje.inject.generator.SimpleModuleWriter.write(SimpleModuleWriter.java:73)
        at io.avaje.inject.generator.ScopeInfo.writeModule(ScopeInfo.java:216)
        at io.avaje.inject.generator.ScopeInfo.write(ScopeInfo.java:304)
        at io.avaje.inject.generator.AllScopes$Data.write(AllScopes.java:95)
        at io.avaje.inject.generator.AllScopes.write(AllScopes.java:53)
        at io.avaje.inject.generator.Processor.process(Processor.java:71)
        at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)
        at org.gradle.api.internal.tasks.compile.processing.NonIncrementalProcessor.process(NonIncrementalProcessor.java:45)
        at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)
        ...
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)
        ... 155 more

@rbygrave
Copy link
Contributor

rbygrave commented Nov 28, 2021

Ok, the problem looks like we are trying to create a custom "TestScope" plus a default scope that also gets the same module name based on the package.

That is, the custom scope called TestScope means that associated module is called TestModule. The module name for the default scope is based on the top level package which is test so that module also gets called TestScope AND they are in the same package (test).

So for example, there are 3 ways to get this to work:

  1. Moving TestClientCustomScope into a different package to test say test.foo ... and it will work / compile.
  2. Changing the package that TestClientDefaultScope is in (so that it's module name is not TestModule) also works
  3. Changing the name of the TestScope to something else would also work (as the custom module name would then not be TestModule).

@rbygrave
Copy link
Contributor

rbygrave commented Nov 28, 2021

This is because the module name gets derived based on:

  • the name of the custom annotation (for custom scopes)
  • the top level package name (for the default scope). In this case that is also test

... so given these 2 naming conventions both modules get called TestModule and both are in the same package - test and this doesn't work (the code generator gets confused and ends up throwing a NPE).

So making one of those 3 changes should sort it all out.

@Travisnv
Copy link
Author

Travisnv commented Dec 1, 2021

I confirmed that both suggestion works for me. Anyway, can we add some documentation about create same name for TestScope around built-in annotation?

@rbygrave
Copy link
Contributor

rbygrave commented Dec 1, 2021 via email

@rbygrave rbygrave self-assigned this Dec 1, 2021
@rbygrave rbygrave added the bug Something isn't working label Dec 1, 2021
@rbygrave
Copy link
Contributor

rbygrave commented Dec 2, 2021

Ok, we now detect this module name clash case and throw a reasonable error:

Attempting to create 2 modules both called test.TestModule. This can occur when a custom scope (named from it's annotation) has a name clash with the default module which can be named from the package. Look to resolve this by either changing the name of the custom scope annotation, or explicitly naming the default scope using @InjectModule(name), or changing the top level package used by the default scope

@rbygrave rbygrave added this to the 6.17 milestone Dec 2, 2021
@rbygrave rbygrave closed this as completed Dec 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants