How to create a test only Maven project? - java

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 :))

Related

What does the "Maven Surefire plugin" means when it test your build?

I am working on understanding Maven and I'm learning about building your Java app with it.
So when I do a :
maven package
It does build my jar as expected but I see in the output console that Maven does build tests (it always say that the test a run and there are no failure).
I researched on the web about that and learned that Maven use a plugin called Maven Surefire. But I can't understand what does that plugin do to my code, what does the tests "means" ? What does the tests do with my code and how it works behind the console ?
The Maven surefire plugin runs the tests you have written. These are usually in the src/test/java folder. If you have none, the plugin does nothing.
Is this only one question? :D
So. Different things are going on.
You create an application with Java. To test the single components / packages / classes that you create most people use JUnit or TestNg. You usually have dedicated test classes that verify your production code behaves as intended without you clicking through all the things on every change.
When you now use maven to run your build the pom.xml file defines a packaging - in your case "jar" since you create a jar file. The packaging defines what set of default plugins run in the defined maven phases. You probably recognize package here. Maven executes all phases up to package and the registered / configured plugins.
To execute those tests maven provides the surefire plugin which supports running JUnit or TestNg tests. If you follow the directory conventions your tests reside in src/test/java and the surefire includes naming convention maven will execute those tests in every build (as this is the best practice). If you also want to write integration tests then there is the failsafe plugin. That plugin is not enabled by default and runs in different maven phases.
So the tests just run your production code - in fact they just do what you implement in the tests. They don't alter it in any way.
The maven introduction documentation has step by step explanations: Maven in 5 Minutes and the Getting Started Guide.
Starting from scratch this is probably a lot. So don't rush this. The build setup and test setup are very important things to have.

Executing a single test in an installed maven jar

I have a jar installed in my local ~/.m2 repo and I would like to execute a single test using the -Dtest option via a python script. I tried using this command on the command line mvn surefire:test -DdependenciesToScan=groupId:artifactId -Dtest=NameOfTest, however it doesn't seem like maven is finding the NameOfTest in the groupId:artifactId dependency and returning back with no tests executed? Any way to execute a single test in an already installed maven artifact?
Typically Java classes in src/test/java (or your corresponding test sources directory) will not end up in a built artifact by maven by default. If you inspect the contents of the JAR, you will likely notice no compiled test classes, which is why maven can't find them.
If you really want your test source compiled into the JAR, there are plugins to help you. Particularly, the standard Maven JAR Plugin.
However, I would suggest you consider carefully why you need test classes in a built artifact. The standard use of test suites is to test the main source code being built. There are some situations that have been argued where having tests in the final artifact are valid, but they are rare and usually can be worked around in other ways ( Related discussion ).

Maven dependency based on argument

I have a Maven project with a number of modules. When building, I have an argument that determines which directory config files and such are copied from, depending on environment it will be running in - ie UAT, DEV, TEST, etc. I do not want to use profiles. Now, I want to package all integration tests into a separate jar that can be executed from command line as well as in integration-test phase. Basically there will be only one test class with one method that does something like
Class.forName("...").getMethod("main").invoke(null, args);
Only problem, is that since I do not want to use profiles Id have to add/remove the dependency on the test solution jar depending on if I want to run integration tests or not. I would like to do something like
mvn clean install -Denv=IT
and let it be. Is there a way to do so?
The standard mechanism for running different kinds of build in Maven is to use profiles (Maven is a highly opinionated build framework, so you are forced to play by its rules)
Your also appear to be building binaries to match the system you intend to deploy. This is generally a bad idea, you are better advised to look at some mechanism that allows the run-time configuration of your application. (In J2EE there is JNDI, but could be just a simple property file). This allows you to certify a single binary that ideally is pushed into a shared repository for sharing between development, test and production.

Separating test and core project with Maven

I already found this post: Separating tests from src with Maven Project?.
I've just started working on a Java project (as I usually use .net), and one of the first > things that strikes me as odd is that in the Maven project there is a /src and a /test
directory where obviously the source code and the tests should go.
In .net I preferred to have the tests in a separate assembly/project, so for example I
would have:
MyProject
MyProject.Tests
That way I dont have to bloat my deployed code with any tests and it makes it easier to
test my code in true isolation and in alot of cases I didnt bother writing tests per
project, I would just have solution wide unit/integration/acceptance tests i.e
MySolution.UnitTests, MySolution.IntegrationTests.
However in Java it just seems to be bundled together, and I would rather separate it out, > however I hear that Maven is a cruel mistress when you want to do things differently to
the default structures.
So to reign this post back in, my main [question is]:
Is there a way to separate out the tests from the project [How?]
Although this question exactly describes what I try to achieve, the thread has not provided the solution for how to do it.
I'd like to know whether there is a way to have a separate project just for (unit) testing with JUnit. I want to have the actual source code in a "core" project and the according tests in a separate "test" project instead of having one single project with src/main and src/test paths.
However, I don't know how to configure the (parent) pom.xml files to achieve that.
So far, I defined a parent pom that declares the two projects as modules. In addition, for each of the two projects, I have a separate pom file declaring the required dependencies etc. Of course, the pom file of the test project defines the core project as a dependency.
I guess I have to configure the pom file of the core project to tell the testing plugin to look in the other project for the tests. But how should such behaviour be configured?
If you follow the Maven conventions (having both the src and test folders) you will have an easier time. Your tests will not be deployed along with your compiled source so I wouldn't worry about bloat. Maven will compile both a jar and a test jar file (assuming you're using jars). If you really want separate src/test modules then yes, the multi-module approach with a common parent is the way to go. The test module would have a dependency on the source module but not the other way around. Really this just amounts to reinventing what Maven is already doing for you though.
In the long run, I think you'd be happier using the conventional approach though as things will go a lot smoother.
Do not pay attention to the naysayers who will try to convince you that you have to do it in one of the established ways or else you will run into trouble. This is cargo cult engineering, and it reflects the cowardice of your average enterprise employee out there, who will rather die than try something different or think outside the box for a moment.
It is perfectly doable to have a huge multi-module maven project, with loads of tests, where not a single module contains both production and test subfolders, and instead every single module is either production, or test. That's the only way they do it in the DotNet world, and I never heard anyone complaining.
There exist situations where you absolutely have to split your modules this way, so maven has no option but to support this. Such situations arise when the dependencies are such that the tests of module A depend on module B which in turn depends on the production code of model A. If both the tests and production code of module A are in the same actual module, this causes a circular dependency, so the project is unbuildable. Such an arrangement is not commonplace, but it does happen some times. When it happens, you have to move the tests of A into a separate module C, which depends on both A and B, and leave only production code on A.
In maven, there is nothing special to it: in production modules you only specify <sourceDirectory>, while in test modules you only specify <testSourceDirectory>. Everything else is done as expected: Both modules have the same parent pom, and the parent pom references them both. JUnit and other test-related dependencies are only included by the test modules. It is so straightforward that it is trivial. (I am not sure what kind of trouble the OP was facing that made him ask the question.)
As a matter of fact, if it was not for the particular maven plugins that people use for running tests during continuous deployment, you would not even need <testSourceDirectory>, you could be using in all modules nothing but <sourceDirectory>. IntelliJ IDEA does not have a problem detecting and running tests even if they are under <sourceDirectory>, but the maven surefire plugin does expect tests to be under <testSourceDirectory>, so you have to use <testSourceDirectory> just to keep that plugin happy.
My personal opinion is that supporting a distinction between production and test subfolders within the same module adds a mind-boggling amount of completely unnecessary complication to build systems. The entire java world would be doing just fine if the feature did not exist at all. Of course this opinion is tentative, since unbeknownst to me there may exist important reasons due to which this distinction is useful. If anyone knows of any such reasons, please enlighten me in the comments.

Using maven to produce production ready output

I have a muti-module maven project, and I created a new module that depends on 3 other modules. (I already have a web app maven module that produces a .war file, now I need this)
This module's output is a .jar, and it has a few resources also which are:
spring context xml file
properties file
Now I want to produce a production ready folder so I can upload it to my server. I am hoping maven can do this for me.
I need the following layout:
myjar.jar
/libs/ (the 3 other maven modules that are dependancies)
/resources
Also, there are some generic dependancies that my parent pom.xml have like slf4j/log4j/ that I also need to package.
It would be cool if I could add a switch to mvn that will produce this like:
mvn clean install production
I plan on running this on my server via the command line.
I think what you are looking for is a Maven Assembly:
https://maven.apache.org/plugins/maven-assembly-plugin/
You can use profiles to disable the generation of the assembly by default (can speed up the development process).
#puce is right in that you may be best to use the Assembly Plugin. What you can't do easily is add another lifecycle 'production' to maven. If you have time you could write a plugin to do this, but you might be better off using a profile called 'production' or 'prod-deploy' to enable the coping into place on the server.
mvn clean install -Pprod-deploy
One thing to remember with maven is that it is very good at building projects in using it's conventions, but it is pretty bad at actually script things to happen out side of the build lifecycle.
I have on several occasions used external scripting tools such as ant/python/bash and groovy to first run the build using mvn then to script the deployment in a more natural language.
The intention of Maven is building not deployment in the sense to production. For this purpose i would recommend things like Chef or Puppet. From a technial point of view it's of course possible to handle such things via Maven. What also possible to build on CI solution like Jenkins. Furthermore it's possible to run a script from Jenkins to do the deployment on production.

Categories

Resources