maven test dependencies of dependencies - maven

I have a large project and i want to add an integration tests module which will depend on every thing and validate interaction between modules.
The issue is that during the test I'm missing the dependency classes
module A uses module B
I have a test on module A testing something that uses module B, and I'm getting an error stating it can't find classes in module B.
I tried surefire but there is no difference.
I know I can and I should mock the classes in B which aren't part of the test but I want a full test that will test everything.

As official Maven documentation declares test scope is not transitive. You need to declare required dependencies explicitly in the pom file(s).

You cannot change this behaviour, but there is usually no need to change this behaviour.
If you want to write a library that is used for testing, then this library should have compile dependencies, but when you use it, declare it with scope test.

Related

Why should we define a scope of a dependency in Maven?

Maven provides a tag for dependencies which can "limit the transitivity of a dependency". I understand, that by defining, for instance, a test scope for a given dependency, this dependency will not be available in other phases (diagram). But I don't get what is the advantage of doing so?
Scopes have three main purposes:
avoid that you use something in your application that you did not want to use (if you declare the implementation as runtime, you cannot accidentally use it in your code).
reduce the amount of transitive dependencies. Especially test dependencies will not become dependencies of the users of your library.
reduce the size of a WAR/EAR: If your container already provides the dependencies, you declares them as provided so that they are not packaged into your application.
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#dependency-scope
You don't need hoe and gun for digging, you just need hoe only.
You don't need JUnit dependency for running on web-server (scope runtime), you need JUnit when you test only (scope test), you don't need JUnit when you package for production.
Another benefit is avoiding version conflicting, avoid unnecessary dependencies redundancy.

Equivalent of api for test dependency in gradle?

I'm having multi module gradle project. In one of my modules I'm having api dependency:
api('de.flapdoodle.embed:de.flapdoodle.embed.mongo')
I want to change it to dependency that will be visible in tests, across all modules. There is a testImplementation dependency but there is no testApi.
I cannot have this dependency on production classpath anymore since I want to use real mongo instance instead of embedded one. On the other hand I have tests in different modules that depend on data access - in that case I want to run those test with embedded mongo on test classpath.
How I can make this dependency visible in all modules tests?
The question (appears to me) is sharing the test code across modules in a multi-module project
Short answer - No - there is direct test dependency share across modules.
To share test code between modules internally via build settings
Official gradle route https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures
Simple hack
testImplementation files(project(':core-module').sourceSets.test.output.classesDirs)
add the above line either individually where you need or in root with subprojects() with appropriate condition
*there are other possible routes as well *
ex: via configuration
child.testImplementation extends parent.testImplementation (or runtime)
testCompileClassPath includes api dependencies so you are all good here, de.flapdoodle.embed.mongo will be visible in your tests.

Dagger 2: Separate Module for testing declared in src/test/java

I have a Maven project and defined a module + component in src/main/java, which Dagger 2 is handling as expected.
Now I want to mock some dependencies for my unit tests. However the dagger-compiler seems to ignore components inside src/test/java.
Is there a way of telling Dagger 2 to also look inside my test source set?
(Not an Android project)
Ok found my mistake. For others having the same problem: This question gave me the correct hint.
Components declared in src/test/java are generated to target/generated-test-sources/. This is an annotation processing default, not Dagger's fault. I just didn't have the idea to look for directories other than target/generated-sources...

Understanding Maven scoping better

I have been struggling to figure out what's the use of scoping that is provided by Maven
as mentioned here.
Why should you not always have compile time scoping? Real life examples would be really appreciated.
The compile scoped dependencies are only used during compilation.
The test scoped ones -- only during tests. Say you have tests using junit, or easymock. You obviously do not want your final artifact to have a dependency on them, but would like to be able to just depend on these libraries while running your tests.
Those dependencies which are marked provided are expected to be on your classpath when you're running the produced artifact. For example: you have a webapp and you have a dependency on the servlet library. Obviously, you should not package it inside your WAR file, as the webapp container will already have it and a conflict may occur.
One of the reasons to have different scopes for dependencies is that different parts of the build can depend on different dependencies. For example, if you are only compiling your code and not executing any tests, then there is no point in having Maven downloading your test dependencies (if they're not already present in your local repository, of course). The other reason is that not all dependencies need to be placed in your final artifact (whether it's an assembly, or WAR file), as some of the dependencies are only used during the build and testing phases.
compile
Will copy these jar files into prepared War file.
Ex: hibernate-core.jar need to have in our prepared War.
provided
These jars will be considered only at complie time and test time
Ex:
servlet.jar will be provided by deployed server, so no need to provide from our prepared War file.
test
These jars are only required for running test classes.
Ex: Junit.jar will be required only for running Junit test classes, no need to deploy these.
Scopes are quite well explained in here:
https://maven.apache.org/pom.html#Dependencies
As a reference, I copied the paragraph:
scope: This element refers to the classpath of the task at hand
(compiling and runtime, testing, etc.) as well as how to limit the
transitivity of a dependency. There are five scopes available:
compile
- this is the default scope, used if none is specified. Compile dependencies are available in all classpaths. Furthermore, those
dependencies are propagated to dependent projects.
provided - this is
much like compile, but indicates you expect the JDK or a container to
provide it at runtime. It is only available on the compilation and
test classpath, and is not transitive.
runtime - this scope indicates
that the dependency is not required for compilation, but is for
execution. It is in the runtime and test classpaths, but not the
compile classpath.
test - this scope indicates that the dependency is
not required for normal use of the application, and is only available
for the test compilation and execution phases.
system - this scope is
similar to provided except that you have to provide the JAR which
contains it explicitly. The artifact is always available and is not
looked up in a repository.
there are a couple of reasons that you might not want to have all dependencies to be default compile scope
reduce the size of final artifact(jar,war...) by indicating different scope.
when you have a multiple-modules project, you have ability to let each module have it's own version of dependency
avoid class version collision by provided scope, for instance if you are going deploy a war file to weblogic server, you need to get rid of some javax jars, like javax.servlet, javax.xml.parsers, JPA jars and etc. otherwise you might end up with class collision error.

Multiple reusable modules in maven

I have a couple of java modules set up in IDEA and I am wanting to mavenize them. These java modules use classes from one another.
I was not quite sure how I should take up this and I decide to add modules on a maven project using IDEA. Hence first I created a maven project, let's name it pm1 which has a class let's name it TempClass1. Now this class can be used in other maven project. Hence I added another maven module - pm11 and tried to use TempClass1 with in pm11. It worked and I notices that IDEA had added module dependency of pm1 in pm11. So whole structure looks as -
But now when I do mvn test from pm11 then it fails with error message package package1 does not exist and it looks to me that it is because package1 is in a different maven project. And I am not sure how I could use classes which reside in a different maven project. I hope I am clear in my question.
You can use classes of other maven projects, as long as there's a proper maven dependency defined in pom.xml. Ensure that the dependency is defined and its' scope is either undefined or relevant (You may have problems if the scope is provided for example).

Resources