14

The Description:

I would like to create a JUnit test using JUnit 5 in Eclipse (Oxygen 4.7.1a). This JUnit test should be inside a seperate src folder called Test. However, I ran into the following problems as I'm new to JUnit and Java 9.

I do not want to use build tools like Gradle or Maven for this.

The Problem:

As I've got two different src folders, one for the projects src and one for the test cases:

  • Do I need two module-info.java files? (one for each src folder)
  • Which modules are required in my module-info.java file for JUnit 5 to work?
Community
  • 1
  • 1
ShadowDragon
  • 2,238
  • 5
  • 20
  • 32
  • **Maven** (the build tool) uses `src/main/java/` and `src/test/java/` so you could try it in a maven project - following new "best practices." It indeed is a question https://stackoverflow.com/questions/41366582/where-should-i-put-unit-tests-when-migrating-a-java-8-project-to-jigsaw – Joop Eggen Oct 11 '17 at 20:06
  • Yeah, I could use maven, but I'm more used to Gradle. Thought I want to try it out without Gradle as I would like to know how it works without such build tools. – ShadowDragon Oct 11 '17 at 20:09
  • https://guides.gradle.org/building-java-9-modules/ But I can understand it; module-info.java must be in the root. And junit often relies on package visibility for class access. Still not encountered a java 9 project with junit tests myself – Joop Eggen Oct 11 '17 at 20:26
  • Possible duplicate of [Where should I put unit tests when migrating a Java 8 project to Jigsaw](https://stackoverflow.com/questions/41366582/where-should-i-put-unit-tests-when-migrating-a-java-8-project-to-jigsaw) ? The solution proposed by Nicolai there shall keep you going. Also not sure why specifically Junit5 for this question is tagged, yet the structure should be similar for any kind of unit tests. – Naman Oct 12 '17 at 04:51
  • Would also await @AlanBateman to throw some light on the context over ... *I hope in time that there will be support from the tools,plugins,test runners...So that regular developers don't need to be concerned with this.* Maybe I've missed this thread altogether from my mails. – Naman Oct 12 '17 at 07:01
  • @nullpointer It's not a duplicate as the question you linked uses maven. JUnit 5 was tagged as this is the newest version of JUnit and from what I read, a lot changed. JUnit 5 has also been tested against Java 9. – ShadowDragon Oct 12 '17 at 13:01
  • Both the questions draw a similar approach of using java and javac and patching modules. The question linked has been answered in general. Irrespective of how the build frameworks implement that approach..Also *JUnit5 has been tested against Java9 and a lot has changed* how does this imply tagging the question with JUnit5? – Naman Oct 12 '17 at 13:09

2 Answers2

8

In general there is no need to modularize your test code (at least I can't think of a valid reason, maybe someone could give a satisfactory counter-example). Only one module-info.java file can (after all, it's not even required to modularize your main code) be present in your main code under src.

Since the module-info.java file will be only in your main source directory and not in the test source directory, then logically it should not depend on the JUnit module. So the questions now become how to compile and run the JUnit test classes by relying on the module (that represents the system under test) and the JUnit module.

To do that, you'll need to use the new options provided by the javac and java:

So assuming you have the following tree:

src
    module-info.java (declares a module called "my.module")
    mypackage
        MyClass.java
test_src
    mypackage
        MyClassTest.java
lib/junit-platform-console-standalone.jar

(note: specifically for JUnit 5, you can use the junit-platform-console-standalone artifact that contains the core JUnit engine and allows running tests in the console; see the user guide)

then you can compile the code as follows:

cd root_dir
javac -d mods/my.module src/module-info.java src/mypackage/MyClass.java

cd test_src
javac -d test_out --module-path ../mods;../lib/junit-platform-console-standalone.jar \
--add-modules org.junit.platform.console.standalone,my.module --patch-module my.module=. \
--add-reads my.module=org.junit.platform.console.standalone mypackage/MyClass.java

and you can run the compiled test class:

cd test_src/test_out
java --module-path=../../mods;../../lib/junit-platform-console-standalone.jar \
--add-modules my.module,org.junit.platform.console.standalone \
--add-reads my.module=org.junit.platform.console.standalone \
--patch-module my.module=. \
--add-opens my.module/test=org.junit.platform.console.standalone \ 
org.junit.platform.console.ConsoleLauncher test.MyClassTest

Awkward commands but that's the cost of not using Maven. I advise you to read about these options in the command documentation after understanding the concept of a module path. An important thing to note here are a couple of options:

--patch-module my.module=.

This is needed because the example test code has the same package (mypackage) as the module my.module. Without it, the module system will complain.

--add-reads my.module=org.junit.platform.console.standalone

This makes junit required by my.module even though it was not declared in module-info.java.

org.junit.platform.console.standalone is the name of the automatic module and is derived from the Jar manifest (as is the case with JUnit 5), otherwise from the name of the Jar file (e.g. in the case of JUnit 4).

Also note that this is what Maven probably does behind the scenes when compiling and running unit tests (see this issue for an equivalent plugin configuration that manually does the above).

What if for some reason, you also want to modularize your unit tests?

In this case, since in the example above the unit tests share the same package, you can include them in my.module and add a requirement to JUnit:

module my.module {
    exports mypackage;
    requires org.junit.platform.console.standalone;
}

If the unit tests were in a different package, you can also split them into two modules (two module-info.java), a my.module and a my.test.module where only the latter requires JUnit.

If you do include test classes in a module, then in the above commands, you don't need --add-reads and --patch-module.

M A
  • 71,713
  • 13
  • 134
  • 174
  • 1
    On the last point, junit has the `Automatic-Module-Name` attribute in the jar manifest (i.e. it's not the file name) - https://github.com/junit-team/junit5/commit/a50e60aa64ecd1f7357409ab34ccd0964e9bee3b – Michael Easter Oct 12 '17 at 00:11
  • (1) That doesn't seem to be dealing with junit5. (2) *it should not depend on the JUnit module*, why? – Naman Oct 12 '17 at 02:07
  • @MichaelEaster My bad, I was trying this example using JUnit 4 and forgot about the context of this question. Updated it now, thanks for the correction. – M A Oct 12 '17 at 03:40
  • @nullpointer I have updated the note about automatic modules in relation to JUnit 5. For the dependency, if the test code and main module are separated, why would the main module require JUnit. The keyword 'requires' implies it is needed by the classes in the module. – M A Oct 12 '17 at 03:45
  • @manouti Why should the test code not be a part of a module instead? and how does it matter what maven does behind the scenes when the OP is not willing to use either Maven or Gradle? – Naman Oct 12 '17 at 03:46
  • *other projects to depend on these tests* source code to depend on unit tests sounds like a bad idea. – Naman Oct 12 '17 at 05:32
  • @nullpointer Do you have an example why would the test code need to be part of a module then? – M A Oct 12 '17 at 06:37
  • I didn't intend to say that is should be part of the module, instead meant, that the answer should reason the cause of considering it to not being a part of the same module. – Naman Oct 12 '17 at 07:00
  • 1
    @nullpointer Fair enough. And I never said that the tests should not be part of a module :) It's just that I can't think of a valid reason why someone would do it, so there is no reason to give for my "no need to modularize tests" statement. – M A Oct 12 '17 at 07:07
  • Never "require" module `org.junit.platform.console.standalone`! It only happens to work as an automatic module and will lead to conflicts if you "read" other module in your descriptor. – Sormuras Oct 13 '17 at 16:03
  • Is this solution still supposed to work with junit 5.5.0?(`junit-platform-console-standalone-1.5.0.jar`) – Flavius Jul 14 '19 at 20:18
0

A reason for the tests being in a module on their own is hexagonal architecture. The test module is a driver adapter swappable with other adapters that run the business logic too.

In my case I'm gonna do it using jaba 9 without maven too.

Here's my article about hexagonal architecture:

https://softwarecampament.wordpress.com/portsadapters/

choquero70
  • 4,470
  • 2
  • 28
  • 48