6

my set up is this. I have project A, and a test project depending on A:

A <- A_t

I also have other projects depending on A (and their tests):

A <- B <- B_t

To simplify some of the testing I introduce a new library helping test stuff based on A:

A <- Atesthelper

So A_t (and B_t) will depend on this test helper, like this:

A <- A_t
^    |
|    v
Atesthelper

However when I create Maven projects (pom.xml) it seems the usual thing is to bundle both the project and the test of that project in the same pom.xml. And I create a new pom.xml for the Atesthelper

So now it becomes:

(A <- A_t)
  ^    |
  |    v
Atesthelper

Which is a circular dependency. Is it possible in the pom.xml to somehow specify that Atesthelper is only a dependency of the test build target, and not the A module in itself?

So the build order should be: A, Atesthelper, A_t. I.e. A and A_t which are specified in the same pom, should not be build at the same time.

Thanks in advance.

Bjarke Freund-Hansen
  • 28,728
  • 25
  • 92
  • 135

4 Answers4

7

If I understand you right, your primary goal is to reuse test classes. A_t and Atesthelper are not Maven projects, they are tests.

Make Maven to create a jar from your src/test/java. See http://maven.apache.org/guides/mini/guide-attached-tests.html

After build of A you will get A.jar and A-tests.jar. A-tests.jar will include Atesthelper and A_t.

Set dependency of B to A-tests.jar (<type>test-jar</type>).

Aleksey Otrubennikov
  • 1,121
  • 1
  • 12
  • 26
1

The problem that you need to solve is the dependency from Atesthelper to A, then everything else will work fine: A depends on Atesthelper, B depends on Atesthelper and both A and B will contain both sources and tests. Atesthelper will be included with scope test in both A and B. That's your target state.

How do you get there? You need to extract the items that Atesthelper is depending on into a separate projects. Typically, these are interfaces or other common functionality, which should be put into a separate project anyway - let's call it ACommon. So your target layout should look like this:

ACommon <- Atesthelper
       ^    ^
       |   /
         A (and also B)

What kind of functionality is Atesthelper depending on in A? Can you move it to a separate project (ACommon)?

nwinkler
  • 52,665
  • 21
  • 154
  • 168
  • `Atesthelper` has to depend on A, as it is effectively a helper to test stuff in `A` and therefore depends on many of the data-only objects in `A` and interacts with objects in `A`. So I don't think that is the correct dependency to break. I was hoping for an answer regarding how to configure maven to build `A` and `A_t` separately. – Bjarke Freund-Hansen Apr 18 '12 at 08:03
  • This sounds like a design issue to me. You're trying to fight the way Maven handles projects and dependencies: One project, one artifact. You might be able to tweak this somehow to your needs, but it will give you more trouble in the long run. Keep it simple and stick to way Maven does things. BTW: Uncle Bob has described something similar many years ago - the Dependency Inversion Principle, worth a read: http://www.objectmentor.com/resources/articles/dip.pdf – nwinkler Apr 19 '12 at 06:12
  • So Maven dictates one project one artifact. Thus, there should be one project (aka pom.xml) for A and another project for A_t. This will solve the issue, but I thought that you "normally" put the project and it's test in the same pom.xml. I understand (and use) DI, but which dependency would you inject in this situation? – Bjarke Freund-Hansen Apr 30 '12 at 07:19
  • 1
    The article is about dependency *inversion*, not *injection*. Two different things. Both implementation and test should be in the same project, that's the standard setup. My recommendation was to break the dependency between your project A and the test helper classes. – nwinkler Apr 30 '12 at 07:36
0

You didn't paste your POMs and I'm not sure if I understand you correctly, but I'll try to help you how I've got it. This is quite common case that usually should be solved like this:

Your Atesthelper artifact (probably jar packaging), that supports testing, should have all its testing-related stuff in the src/main directory (so classes in src/main/java, resources in src/main/resources, etc.), not src/test! All its dependencies, so A, but also stuff like JUnit, EasyMock (all stuff that testing-support classes need) you declare with compile scope, which is the default one of course. Don't use test scope here! Finally, in A and B artifacts, declare Atesthelper as dependency of test scope.

That solution works great for me for many years. It is clean and straigt about dependencies (they're transitive in contrast to <type>test-jar</type>-based solution if you know what I mean). Anyway, just use it. You'll be happy ;).

Michał Kalinowski
  • 16,925
  • 5
  • 35
  • 48
  • 1
    Does not address the issue of the circular dependency. – nwinkler Apr 16 '12 at 15:06
  • I think that the circular dependency problem will disappear by using this solution. As I said, I've never had any problem with that. IMHO it should work really well. – Michał Kalinowski Apr 16 '12 at 15:13
  • I guess this could work if you first build `A` and `B` with [skipping the tests](http://maven.apache.org/general.html#skip-test), then build `Atesthelper`, and then build `A` and `B` again with tests. – Björn Pollex Apr 17 '12 at 06:38
  • 1
    @MichalKalinowski: This is (kind of) what I have tried, I was thinking that using scope correctly should be the solution. However, I cannot get around that `A` and `A_t` should not be build right after each other, `A` first, then `Atesthelper` and then `A_t`, and I don't know if maven can do this when `A` and `A_t` are specified in the same `pom.xml`? – Bjarke Freund-Hansen Apr 18 '12 at 07:51
  • Yeah, this cannot work like this. Probably you should user @nwinkler solution or maybe rethink things. The responsibility of `Atesthelper` helper is somehow not clear for me, to be honest. If it shoule be some kind of common testing support module, it should depend on common classes module, not some specific stuff, because then you have specific test helper. – Michał Kalinowski Apr 18 '12 at 08:00
  • 1
    that is exactly the problem, you write a Module A and a Module B. B depends on A, so far no problem. now you want to write a test for the Module A: AT. AT now obviously depends on A, but can depend on B as well. for those 3 projects, there is no problem at all. but the maven structure encurages to put everything from AT into the test folders of A, which then causes the problem that A (because of AT) depends on B, and B depends on A. – benez Feb 07 '17 at 21:48
0

The cleanest way to solve this issue is to keep the projects separated. There are frameworks like Maven that encourage you to put Classes and Test Classes into one single project. Eclipse PlugIn projects for example have separate test projects. Making A_t a sub-project of A sounds like the best solution, since you can reuse whatever dependencies you want in that test project without worrying about the impact on A.

This scenario will arise more often and you might not want to bother your project design with dependencies of tests. Those tests should be independent and not influence your class design.

benez
  • 1,856
  • 22
  • 28