Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I open packages and require dependencies on test scope modules only for JUnit testing

I'm migrating a jar project from java 10 using classpath to java 11 using the java 9 jigsaw modules. There are JUnit5 tests for the project. The test dependencies are provided at test scope by maven. How to make all packages open for testing but not open when the module is used by another project?

The jar project is just providing a few classes (like a utility project) for other projects (so no main class needed).

The project got 5 packages at /src/main/java/a/b/c/. 2 of them should be accessible for projects using this jar. The other 3 are for internal use only (used by the accessible ones). The tests are located at /src/test/java/a/b/c/. These tests have dependencies (JUnit, mockito, junt-params) provided in test scope, since the tests are not relevant for the projects using this jar

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

I have provided a module-info.java at /src/main/java/ :

module moduleName {

requires java.base;

exports a.b.c.package1;
exports a.b.c.package3;
}

so now the public classes in package 1 and 3 should be accessible to other projects as expected (I have not been able to verify this yet).

Running the Tests now results in java.lang.reflect.InaccessibleObjectException: Unable to make a.b.c.package1.collections.SomeTest() accessible: module moduleName does not "opens a.b.c.package1" to unnamed module @6a84a97d

when I open the packages (with opens) everything runs smooth. But now all packages are now opened. I expect package 2, 4 and 5 to be only accessible while testing and 1 and 3 should not be open for reflection (so only exported).

I came to think, since maven tells me unnamed module @6a84a97d, this might be a module created for testing. That made me try adding a module-info.java at /src/test/java/ for testing.

module moduleNameTest {
requires moduleName; // the code to test
requires java.base;  // java.base could be transient on moduleName

// test dependencies
requires org.junit.jupiter.api;
requires org.junit.jupiter.params;
}

now maven (3.5.4) states:

src/test/java/module-info.java:[3,20] module not found: moduleName
src/test/java/module-info.java:[4,31] module not found: org.junit.jupiter.api
src/test/java/module-info.java:[5,31] module not found: org.junit.jupiter.params

Technologies:

  • java openJDK 11
  • mvn 3.5.4
  • JUnit 5.3.0
  • Surefire Plugin 3.0.0-M3
  • mockito 2.21.0

As stated earlier I expect package 2, 4 and 5 to be only accessible while testing and the tests to be run on building the jar with maven. Package 1 and 3 should be exported for use in other projects but not open for reflection (so only exported not opened).

If you need additional information don't hesitate to ask.

Thanks in Advance

Kevin

like image 881
Kevin Kussmaul Avatar asked Jan 07 '19 05:01

Kevin Kussmaul


People also ask

Why do we need JUnit dependency?

The junit-jupiter-engine dependency ensures that the Maven Surefire Plugin can run tests which use JUnit 5. The junit-jupiter dependency is an aggregator artifact which simplifies the dependency management because it ensures that the required dependencies are found from the classpath.

What is the name of the package that you use for JUnit?

The org. junit package contains many interfaces and classes for junit testing such as Assert, Test, Before, After etc.

How do you create a test package?

Right-click the test root folder or package in the test root folder in which you want to create a new test and select New | Java Class. Name the new class and press Enter . Press Alt+Insert and select Test Method to generate a new test method for this class. Name the new method and press Enter .


1 Answers

"Welcome to Testing In The Modular World", Kevin.

I compiled a blog about that topic here: https://github.com/sormuras/testing-in-the-modular-world

Basically, when it comes to white-box testing, you need to tweak the module system either at test compile or test runtime to allow testing frameworks to by-pass the module system barriers.

I guess, you're on the right track ... maybe Surefire does the wrong thing? Want to give https://github.com/sormuras/junit-platform-maven-plugin I wrote a shot? This plugin supports black- and white-box testing out of the box. Especially, this plugin shines, when you provide a test/java/module-info.java test module descriptor.

See this "picture" for how to organize modular tests without touching the main module descriptor:

src ├── main │ └── java │ ├── foo │ │ ├── PackageFoo.java │ │ └── PublicFoo.java │ └── module-info.java <------------------ module foo { exports foo; } ├── test │ └── java .--- open module foo { │ ├── foo / exports foo; │ │ └── PackageFooTests.java / requires org.junit.jupiter.api; │ └── module-info.[java|test] <----< } └── it \ └── bar °---- --add-reads └── src foo=org.junit.jupiter.api └── test --add-opens └── java foo/foo=org.junit.platform.commons ├── bar │ └── PublicFooTests.java └── module-info.java <------ open module bar { requires foo; requires org.junit.jupiter.api; }

This pattern should be easy to adopt to your setup as well.

Related question: How do you organize tests in a modular Java project?

like image 143
Sormuras Avatar answered Sep 28 '22 01:09

Sormuras