How to compile test code in a modular project?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

How to compile test code in a modular project?

Till Brychcy

A common source structure (e.g. used by maven and gradle) is that tests are in separate source directory with separate output directory
and are in the same packages as the code that is being tested, so the tests can access code elements that have package visibility.

Also, test dependencies like junit should not be referenced in the module-info.java, so „main" code cannot accidentally access them.

The question is, how to compile the tests with javac (version 9.0.1)?

The following example is more detailed in https://bugs.eclipse.org/bugs/show_bug.cgi?id=520713  but I think my question should
be clear without the details.

Compiling the main code is no problem (module-info.java defines module m):
    javac -d target/classes src/main/java/module-info.java src/main/java/p1/*.java

I think the following would be correct according to http://openjdk.java.net/jeps/261
   javac -d target/test-classes -cp target/classes --module-path junit-4.8.2.jar --add-reads m=junit src/test/java/p1/P1Test.java
but there is a warning: "warning: module name in --add-reads option not found: m" and then there are errors because junit is not found.

The following versions don't work:
   javac --module=m -d target/test-classes -cp target/classes --module-path junit-4.8.2.jar --add-reads m=junit src/test/java/p1/P1Test.java
   javac --module=m -d target/test-classes --module-path target/classes:junit-4.8.2.jar --add-reads m=junit src/test/java/p1/P1Test.java
Both give: "error: module source path must be specified if -m option is used"

I tried to use --module-source-path, just to have one:
 javac --module=m -d target/test-classes --module-path target/classes:junit-4.8.2.jar --module-source-path src/main/java --add-reads m=junit src/test/java/p1/P1Test.java
But this gives "error: module m not found in module source path" (I guess the problem is that there  is no "m" subdirectory in src/main/java)

I *can* compile the test code as follows:
   javac -d target/test-classes -cp target/classes --module-path junit-4.8.2.jar --add-modules junit src/test/java/p1/P1Test.java
As I understand it, javac compiles this as part of the unnamed module, so I can e.g. use "import java.rmi.*;" in P1Test.java and no error is reported.
So this is not a "correct" solution.

Is compiling code test code (or any code to be used with --patch-module) as part of the module actually possible with javac?

Reply | Threaded
Open this post in threaded view
|

Re: How to compile test code in a modular project?

Christian Stein
On Wed, Nov 8, 2017 at 9:03 PM, Till Brychcy <[hidden email]>
 wrote:

>
> [...]

Is compiling code test code (or any code to be used with --patch-module) as
> part of the module actually possible with javac?
>
>
Hi Till,

I compiled an example called "sawdust" that show-cases how you
can compile and run projects that organize main and test sources
in modules. It's available at https://github.com/micromata/sawdust
It is based on Java 9 and JUnit 5, but you may adopt the process
to JUnit 4 or older.

Basically "black box"[2] testing is the easy part. Your test sources can
be considered as application modules that happen to use your
modules along with JUnit/AssertJ/... modules. Here you can test
the module API or the exported types. No need to "--patch-module".

"White box" testing needs some more setup. I like the approach
pro[1] is taking here: first you (manually) merge the module
descriptors and then you patch the types declared in the "main"
source set into the source path of your "test" source set.

Hope that helps -- and only because it works for me, doesn't mean
it's the intended or recommended way compile and run tests
on the module path.

Cheers,
Christian

[1] pro https://github.com/forax/pro
[2] black box https://github.com/micromata/sawdust/tree/master/
modules/user.view/src/test/java/user.view
[3] white box https://github.com/micromata/sawdust/tree/master/
modules/sawdust.alpha/src

On Wed, Nov 8, 2017 at 9:03 PM, Till Brychcy <[hidden email]>
wrote:

>
> A common source structure (e.g. used by maven and gradle) is that tests
> are in separate source directory with separate output directory
> and are in the same packages as the code that is being tested, so the
> tests can access code elements that have package visibility.
>
> Also, test dependencies like junit should not be referenced in the
> module-info.java, so „main" code cannot accidentally access them.
>
> The question is, how to compile the tests with javac (version 9.0.1)?
>
> The following example is more detailed in https://bugs.eclipse.org/bugs/
> show_bug.cgi?id=520713  but I think my question should
> be clear without the details.
>
> Compiling the main code is no problem (module-info.java defines module m):
>     javac -d target/classes src/main/java/module-info.java
> src/main/java/p1/*.java
>
> I think the following would be correct according to
> http://openjdk.java.net/jeps/261
>    javac -d target/test-classes -cp target/classes --module-path
> junit-4.8.2.jar --add-reads m=junit src/test/java/p1/P1Test.java
> but there is a warning: "warning: module name in --add-reads option not
> found: m" and then there are errors because junit is not found.
>
> The following versions don't work:
>    javac --module=m -d target/test-classes -cp target/classes
> --module-path junit-4.8.2.jar --add-reads m=junit
> src/test/java/p1/P1Test.java
>    javac --module=m -d target/test-classes --module-path
> target/classes:junit-4.8.2.jar --add-reads m=junit
> src/test/java/p1/P1Test.java
> Both give: "error: module source path must be specified if -m option is
> used"
>
> I tried to use --module-source-path, just to have one:
>  javac --module=m -d target/test-classes --module-path
> target/classes:junit-4.8.2.jar --module-source-path src/main/java
> --add-reads m=junit src/test/java/p1/P1Test.java
> But this gives "error: module m not found in module source path" (I guess
> the problem is that there  is no "m" subdirectory in src/main/java)
>
> I *can* compile the test code as follows:
>    javac -d target/test-classes -cp target/classes --module-path
> junit-4.8.2.jar --add-modules junit src/test/java/p1/P1Test.java
> As I understand it, javac compiles this as part of the unnamed module, so
> I can e.g. use "import java.rmi.*;" in P1Test.java and no error is reported.
> So this is not a "correct" solution.
>
> Is compiling code test code (or any code to be used with --patch-module)
> as part of the module actually possible with javac?
>
>
Reply | Threaded
Open this post in threaded view
|

Re: How to compile test code in a modular project?

Alan Bateman
In reply to this post by Till Brychcy
On 08/11/2017 21:03, Till Brychcy wrote:

> A common source structure (e.g. used by maven and gradle) is that tests are in separate source directory with separate output directory
> and are in the same packages as the code that is being tested, so the tests can access code elements that have package visibility.
>
> Also, test dependencies like junit should not be referenced in the module-info.java, so „main" code cannot accidentally access them.
>
> The question is, how to compile the tests with javac (version 9.0.1)?
> :
>
> Is compiling code test code (or any code to be used with --patch-module) as part of the module actually possible with javac?
>
Yes, --patch-module is needed to compile the tests "as if" they are part
of the module, e.g.

    javac --module-path classes:junit.jar --patch-module m=src/test/java
--add-reads m=junit -d test-classes \
        src/test/java/p1/P1Test.java

Are you using Maven? If so then the maven-compiler-plugin already does
this for you when the project is a module.

-Alan

Reply | Threaded
Open this post in threaded view
|

Re: How to compile test code in a modular project?

Till Brychcy
> Am 09.11.2017 um 09:29 schrieb Alan Bateman <[hidden email]>:
>
> Yes, --patch-module is needed to compile the tests "as if" they are part of the module, e.g.
>
>   javac --module-path classes:junit.jar --patch-module m=src/test/java --add-reads m=junit -d test-classes \
>       src/test/java/p1/P1Test.java
>

Thanks a lot, Alan!

The surprise for me was that --patch-module is used for source folders, too. I thought it was only for binaries.

But I noted I also have to add "--add-modules=junit" or the "--add-reads m=junit" will give an error that module junit cannot be found.
So the command has to be:
   javac -d target/test-classes --patch-module m=src/test/java --module-path target/classes:junit-4.8.2.jar --add-modules=junit --add-reads m=junit src/test/java/p1/P1Test.java

I’m not sure if that is a bug or a feature.  BTW, I noted that "javac -help" doesn’t mention --patch-module and --add-reads at all (only --add-modules)

Reply | Threaded
Open this post in threaded view
|

Re: How to compile test code in a modular project?

Jonathan Gibbons


On 11/09/2017 01:05 PM, Till Brychcy wrote:

>> Am 09.11.2017 um 09:29 schrieb Alan Bateman <[hidden email]>:
>>
>> Yes, --patch-module is needed to compile the tests "as if" they are part of the module, e.g.
>>
>>    javac --module-path classes:junit.jar --patch-module m=src/test/java --add-reads m=junit -d test-classes \
>>        src/test/java/p1/P1Test.java
>>
> Thanks a lot, Alan!
>
> The surprise for me was that --patch-module is used for source folders, too. I thought it was only for binaries.
>
> But I noted I also have to add "--add-modules=junit" or the "--add-reads m=junit" will give an error that module junit cannot be found.
> So the command has to be:
>     javac -d target/test-classes --patch-module m=src/test/java --module-path target/classes:junit-4.8.2.jar --add-modules=junit --add-reads m=junit src/test/java/p1/P1Test.java
>
> I’m not sure if that is a bug or a feature.  BTW, I noted that "javac -help" doesn’t mention --patch-module and --add-reads at all (only --add-modules)
>

Use "javac -X" or "javac --help-extra" to see help on additional
options, such as less common or more advanced options.

-- Jon