I'd like to run tests with JUnit 5 on Java 9 modular project in Eclipse, with no Maven, Gradle or all that fancy stuff. So I have src/main/java path where module-info.java and module's packages live and also src/test/java where all the test classes are. Id est business as usual, prior to the Jigsaw module system. I have Eclipse Oxygen.3a (4.7.3a) an Java 10.0.1.
I've seen some video from Eclipse showing, how to add JUnit test to modular project, but this flabbergasted me deeply: they put required keyword into module-info.java of a module, binding it to JUnit module. Is that actually even correct?
I've seen also all these --patch-module/--add-reads solutions (when we're talking about working in a console) and it seems like it's the proper way to do it, but I have no idea, how to achieve that in Eclipse without binding module under test to JUnit module. Is that even possible in Eclipse (without Maven and s.o)?
I tried to solve this problem for quite a while, too. My approach is to add a filter to the source code directory for src/main/java that filters out the module-info.java. This allows to have a different module-info.java in src/test/java. It will be this one that gets copied to the output folder. This way you can run your unit tests from within the IDE and use the other one for the final build. However, you need to keep the content of the one in src/main/java updated yourself.
Right click on the project > Properties > Java Build Path > Source
Select the src/main/java entry, click Edit > Next > Exclusion Patterns > Add
Related
I have a project 'java11-core' that generates a test jar artifact to share with project 'java11-app'. These projects build fine with command line Maven, but within Eclipse, the classes shared in the test jar cannot be found.
Version Info:
Apache Maven 3.6.0 (command line and Eclipse)
Java version: 11.0.1, vendor: Oracle Corporation
Eclipse IDE: Version: 2018-09 (4.9.0)
M2E Plugin: 1.9.1.20180912-1601
I originally created these to projects as tradition non-JPMS projects. These projects compiled and ran tests normally as expected. After I added module-info.java to both java11-core and java11-app, the Eclipse compiler could not recognize the shared test files from the core project.
Here is a snapshot of the package explorer for an overview of the project structure.
The added java11-app and java11-core module-info contents respectively:
module com.java11.app {
exports com.java11.app;
requires com.java11.core;
}
module com.java11.core {
exports com.java11.core;
}
As you can see, I do not export the test utilities package from com.java11.core. I do not want to export the test packages because this would make the test classes publicly available. I also do not wish to introduce a new test project, because in real-world scenarios, this is very likely to require cyclic dependencies between test utilities and the projects they assist in testing.
Build errors for in AppTest.java. The failure reported by Eclipse is interesting is that it does not claim it cannot find the CoreTestUtil class, but rather:
The type com.java11.test.core.util.CoreTestUtil is not accessible AppTest.java /java11-app/src/test/java/com/java11/app line 8 Java Problem
CoreTestUtil cannot be resolved AppTest.java /java11-app/src/test/java/com/java11/app line 21 Java Problem
My assumption is that the lack of an export for this package from java11-core and/or the lack of a requires for this package in java11-app make eclipse believe the access is restricted, even though the classes exist in a separate test-jar.
The module path for java11-app shows it includes java11-core as a module, and the Without test code is set to No.
I know I am working with newly release features and suspect that sharing test classes across Eclipse JPMS project is not yet supported. But, I am not sure where to look (Eclipse? M2E plugin) for an update on it being supported. I am also not aware of a work-around that would allow me to be productive while adopting JPMS for my software projects.
For those that believe test utilities should not be shared this way...
This subject has been characterized as a best-practice issue that should be resolved by refactoring test utilities into a separate module. I respect this perspective, but in attempting to follow that guidance, I found myself being forced to violate other best-practices, including DRY (Don't Repeat Yourself), and cyclic dependencies between packages.
It is common for a test utility to emerge while developing a module that both assists in effective testing of that module, as well as depends on that module. This creates a cycle if those utilities are pulled out to separate module. Furthermore, some of these utilities can be equally useful when testing other modules that depend upon that module. This creates duplicate code if those utilities are copied to a new test module for dependents. This reasoning may have been why Maven 'test-jar' support was originally added.
Eclipse does not support multiple module-info per project: in whatever source folder (main or test), you must only have one module-info.
From Eclipse point of view, your only luck is to create a new Java project referencing the other and with its proper module-info/exports:
module mod.a {
exports com.example.a;
// com.example.a.Main
}
module mod.a.tests { // (1)
exports com.example.a.tests;
// com.example.a.tests.MainUtils calling com.example.a.Main
requires mod.a;
}
In case (1), you will have problems if you don't use mod.a.tests: Java will never find com.example.a.Main, probably because the second project shadows the first project.
I am not an OSGI expert, but I think that's one of those reason for why most Eclipse plugin do have a main and test projects: org.eclipse.m2e.core is patched by org.eclipse.m2e.core.tests
However module-info does not have any knowledge of "patches": you may patch a module on command line (java --patch-module), but not in module-info itself: perhaps Eclipse could do that on your behalf, but it don't.
As you can see, two project in Eclipse = two Maven module.
In the case of Maven, you can certainly create other artefacts with the same build (and I do think it tends to pollute the dependencies, because every time your secondary artefacts will requires a dependency, it would have to go to the common scope).
This can be done using maven-compiler-plugin, maven-shade-plugin and maven-jar-plugin:
I think you should not rely test-jar because you want to emulate the --patch-module of Java by merging the classes and test-classes directories.
You don't want to import this project in Eclipse due to multiple module-info; or you must ensure that its module-info is only visible to Maven (you can use a profile + m2e.version do detect m2e and disable it).
I fully agree with you. Why should I only use the src-main code from some core module when I also could inherit some src-test functionalities?
But how to handle the scope problem? When I use the "test"-scope I loose the relation to the src-main code. When I dont use the test scope I loose the relation to the src-test code.
My core test code does not change very often, so to get the stuff working in Eclipse
I install the test-jar to my local repository and everything works fine.
In my directory structure I use src only. And I am only writing up Selenium Junit tests. So I would only be writing test classes. How can I configure maven to test only with src ?
Tried pointing to same output directory, but mvn clean test cannot run the test files.
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<testOutputDirectory>${project.build.directory}/classes</testOutputDirectory>
If I add below entries, I see the project gets built twice.
<sourceDirectory>${project.basedir}/src</sourceDirectory>
<testSourceDirectory>${project.basedir}/src</testSourceDirectory>
Even thus this may be possible using Maven it will brake the underlaying convention. Beeing at the point where a "clean structure" or client requirements deny following the convention i would question Maven as the right choice for your build process.
BUT: Most Java developpers would consider the maven structure "clean", expecially because production/busines-code is separated from test code allowing for example to deploy your application including all of the unit- and integrationtests to a Jenkins server for continous integration while a deployment to the production environment may not contain any test classes at all.
Since per definition only "productive" code belongs to src/main/java even if you would have some sort of test-base with your own TestRunners, Factorys, etc. under src/main/java the according "Tests of the Testbase" would reside in src/test/java.
If i was you i would realy consider to refactor the project and move your Testclasses to src/test/java (i leave it open to you on how you argument about convention over configuration and related topics :))
I'm developing a project in Eclipse JDT, that has optional dependencies on OSGI - that is, it supports being used as an OSGI bundle, and if it is used as a bundle inside an OSGI environment, it will also reference some classes from OSGI.
Now I want to write JUnit test cases for both running inside OSGI and running without OSGI, included in two different test suites. The OSGI tests are run as JUnit Pulg-in Tests and the Non-OSGI tests should be run as normal JUnit Tests.
Now I have the problem, that I couldn't find any way in Eclipse to exactly specify the classpath for the JUnit Test Run Configuration and exclude the optional OSGI jars.
Is there any way to exclude jars or modify the default classpath for an Eclipse Run Configuration?
If not, does anyone have a suggestion, how one should setup JUnit tests in such a case?
The only solution I was able to find is, to create a jar file from my unit tests and run the tests without OSGI from a different project with the test jar file on the classpath. But I would prefer a more elegant solution, ideally without the necessity of a second test project.
With the help of Gimbys comment, I was able to solve the problem. Although it is not possible in Eclipse to modify the default classpath generated by JDT, it is possible to entirely remove the default classpath and then add your own classpath in the classpath tab of the Runtime Configuration.
To remove the default classpath, one has to select the root entry that is named after the currently run project, and then click on the "remove" button. After that one can add all the jar files and projects that should be loaded in the classpath. The downside of this approach is, that jar files, that are normally provided by Eclipse plugins like e.g. junit.jar, must then also be selected manually (e.g. by adding it to a library folder of the project or by selecting the external jar in the plugins directory of the Eclipse installation folder).
I would suggest that you split up your project in 4 separate projects:
Logic: This package contains all the logic, so basically what your program/plug-in does
Logic.plugin: This Project resembles a Plugin-Project (OSGI-Bundle). This project contains only configurations needed for your plugin and everything dependent on osgi. It has a dependency on your Logic Project.
Logic.plugin.test: All the test cases for your osgi bundle. It is the normal plugin approach to split up logic and test cases
Logic.cli: This project contains the command line interface (or whatever your alternate application is). This also depends on the Logic project.
If your CLI project is only very small you may merge it with the Logic project.
I'm working on a swing project, using maven2 (from command-line) and eclipse (without maven integration). So, I generate the eclipse project through maven eclipse plugin (mvn eclipse:eclipse), import it inside eclipse, and do all my work.
My problem is: when I run my app in eclipse (as a Java Application), I can't find none of the resources that are in my src directory. Digging for information on my problem, I get into this answer from another question. So, I compared the output from the following instructions:
MyClass.class.getResource("/").getPath();
MyClass.class.getProtectionDomain().getCodeSource().getLocation().toString();
Those gave me the following outputs, respectively:
${workspace_loc}/${my_project}/target/test-classes/
file:/${workspace_loc}/${my_project}/target/classes/
Checking the above locations, I could see that the former is empty, while the other one contained all my compiled classes and resources. So, I came to the conclusion that the classloader is looking for my resources in the wrong place. So, I think I have three questions:
Is my understanding correct?
If so, how it does to find the classes it is loading?
How do I solve this?
UPDATE: I've changed my code, so instead of invoking MyClass.class.getResource(...) or MyClass.class.getResourceAsStream(...), I'm now using ClassLoader.getSystemResource(...) and ClassLoader.getSystemResourceAsStream(...). In this way, everything is working fine in eclipse. I just don't know exactly why. Any hint on this?
Two possibles cases for me :
You are using eclipse to compile your project. Then eclipse is configured to exclude (or not include) resources in the src folder. You can set it in Project/Properties/Java Build Path/Source. Then you expend your src folder, and ensure you have something like "Included All", "Excluded None".
You run your maven application using maven to compile and not eclipse, even though you are using eclipse as your IDE. Then by default maven will not copy resources from the source folder to the output folder... Because it is not the standard maven way of doing things. Thus the resource are missing from the classpath and you don't find them. Just change your maven configuration to also include resources from your source folder.
I think you have to add src/main/resources to the build path. This is done in Project Properties > Build Path > Source. Here is how the standard maven project looks:
In future when using Eclipse I suggest to use m2eclipse plugin and create project using it. This will automatically make sure that all these folders are in the build path.
Try this:
Run configurations... -> Classpath -> User Entries -> Advanced... -> Add Folders
Can you try loading the resources using below?
this.getClass().getClassLoader().getResourceAsStream(propertyFileName)
This might be useful information
Eclipse Maven plugin has its own Classpath Container that conflicts with generated class paths when enabled.
What I would suggest is stop using eclipse:eclipse (sorry - harsh I know). I used it for about 8 months, cant believe it took me that long, and used M2Eclipse. M2Eclipse is an eclipse plugin in which you do the following.
Enable Dependency Management.
Update Project Configuration
(In Eclipse) Project -> Build Project
(In Eclipse) Run Application
It may not seem it, but its a much easier and less frustrating way of doing it.
Before, with eclipse:eclipse. You would have to run it then hit refresh and hope that everything is configured - if you have a multi-module pom things can really go wrong.
For me the Files within the WEB-INF were not getting included. Hence I added them to Buildpath (Project -> Build Path -> Configure Build Path -> Add folder (project/src/main/webapp). This resolved the issue.
Our software is written in Java and comprise many (7) projects.
These projects are Netbeans ant projects.
I'm considering to converting them to maven2.
Where can I find some hints for doing such thing?
Don't read that book. It will only make you confused. Read this book instead: "Maven - The definitive guide" http://www.sonatype.com/books/maven-book/reference/ .
Also, the maven site has a lot of information, but the structure is terrible so you'll need to use google to navigate in it.
Here is my suggestion:
Do this by hand, not with "automagic" "help" from the IDE. Maven integration doesn't work that good yet, not in any IDE.
Make sure you program project is divided into modules under a common umbrella module, so that each module produces a single binary artifact (jar, war,...) possibly accompanied by the javadoc of the source code behind that artifact, a zip with the source code etc. The basic principle is that each module produces a single artifact, containing all the non-test-code under that module. You can do this while the project is still built by ant.
Each module should conform to the standard maven directory layout. The build destination is under [module]/target/[output-type, e.g. "classes"]. The source code is under [module]/src/main/[src-type e.g. "java"] and [module]/test/[src-type]. The artifact consists of all the code under src/main, and none of the code under src/test, as it built to the target directories. You can do this while the is still built by ant.
Start by transforming the sub-module that has no dependencies on other modules in the project.
Now you can create the parent maven module pom.xml with artifact type "pom", consisting of one of the modules below. Make a child module for the first submodule (the one with only external dependencies), using the umbrella module as "parent". Remember that you need to specify version for the parent. Remember to add the child module as a "module" in the parent too. Always use ${project.version} as version in the child modules when you create multi-module projects like this. All modules under a parent must be released simultaneously in a single operation, and if you use this setting maven will make sure the version fields stay the same across all modules and gets updated everywhere during the release. This may make it difficult to re-use the existing numbering scheme, but that doesn't matter. You are never going to run out of version numbers anyway.
Add the necessary dependencies, and make sure you can build the parent and the child module together using the command "mvn clean install" from the parent module.
Proceed with the rest of the modules the same way. Dependencies to other modules under the same parent project should also use ${project.version} as the "version" they are depending on, meaning "the same version as this". NOTE THAT in order to build, the module you are depending on must be built using "mvn install", so that it gets deployed to you local (computer) repository. Otherwise the depending module will not be able to find the classes. There are NO source-code dependencies between modules in maven, only dependencies to built and packed versions installed in local and remote repositories. This can be very confusing if you come from ant-projects. Build from the root module until you get comfortable with this. It takes two days.
Don't use maven integration in IDEs. It is a bad idea. Use "mvn idea:idea" or "mvn eclipse:eclipse" to set up your workspace as a non-maven ordinary IDE project. The inter-module dependencies mechanisms in maven and the IDE aren't identical and will never be. Also, if you have several mavenized projects with dependencies in between, you want to have several of these in your workspace with dependencies set up between. You can do this with mvn idea:idea / eclipse:eclipse if you create a separate maven project file called "workspace.xml" (or whatever) in the same directory as parent module, set up as a multi-module project containing modules "." and "../otherproject" (only one-way reference here, no parent ref back). If you run "mvn idea:idea / eclipse:eclipse -f workspace.xml" you get a workspace with all these modules linked together. No IDE integration lets you do that. This sound like a lot of extra work, but the workspace.xml-file is really small. It doesn't have to contain all that dependency stuff and all that, only the reference to the modules you want to bind together in your IDE.
I did a succeful migration of NetBeans Ant project to Maven project using the instruccions by Joseph Mocker here: http://forums.netbeans.org/ptopic55953.html
I cite the important part:
close the project
rename the build.xml, nbproject files/folders to something so NB won't recognize them.
close and restart NB (so any memory cache knowledge of the project is gone)
copy in an empty pom from some other project.
open the project back up in NB (NB should now identify it as a maven project)
rearrange the files to follow the maven way (™)
This won't be an easy task since Maven2 expects the files to be organized in a specific way. Anyway Better Builds with Maven is a free book that should get you started. It will help you understand Maven and it also has a chapter on migration.
I discovered that the migration is not necessary. The real requirements that I need was automatic download of dependencies (libraries).
This is also achieved by Ivy which nonetheless uses maven repositories.
I solved converting project from ant to ant+ivy with IvyBeans.
I have built a script to migrate Ant builds to Maven. You can find more information here:
https://github.com/ewhauser/ant2maven
It won't help you with fixing your directory structure and or any additional Ant tasks, but it removes a lot of the tedious steps to get started.