I did not have time to read it all but I have to say that even the first
point is bad.
Many people want to share test JAR as they initially think it is a good
idea. And then the problems would come.

sharing stubs? This domain/project may not fit to other domain/project, and
it creates dangerous cohesion.
sharing testing utility classes? Maybe, it depends. It must be universal
and independent of the project's domain. Do it in a separate Git project.
sharing JUnit superclasses? The inheritance must be domain/business
independent. It must be only a technical class. Do it in a separate Git
project.

T



On Thu, Jul 1, 2021 at 7:15 PM Brandon Mintern <mint...@everlaw.com> wrote:

> Hello all,
>
> I'm running up against an issue that I'm sure has come up countless times.
> How can we share test dependencies in a principled way? I would like to
> configure our projects such that:
>
>    1. For a project *P*, its tests are associated with the project, so that
>    `mvn install` from the project directory *p/* fails when P's tests fail.
>    2. Some of P's testing functionality (e.g., stubs, testing utility
>    classes, JUnit superclasses) are packaged for use in the tests of other
>    projects* D* that depend on P.
>    3. P's shared testing functionality has dependencies on P. For example,
>    P defines a repository interface R, and its tests define and use an
> RStub
>    that implements R. We want to package RStub for use by D's tests.
>    4. When D declares a scope:test dependency on P's testing functionality,
>    automatically pull in the transitive dependencies of that testing
>    functionality.
>    5. Avoid cycles in the Maven dependency graph.
>
> Some things I've tried so far:
>
>    - Create test-jars for P. This fails on #2 and #4:
>    - The test-jars include all of P's test classes instead of just the
>       testing functionality that needs to be shared for use by D's tests.
>       - All transitive dependencies of P's test-jar must be manually
>       specified with scope:test in the D's POM.
>    - Extract the stubs to an independent "P - Stubs" project, which P's
>    tests depend on.
>       - p-stubs depends on P.
>       - Stubs, testing utilities, etc. go in p-stubs/src/main/.
>       - P depends on p-stubs with scope:test.
>       - D depends on p-stubs with scope:test.
>       - This fails on #5: it causes a cycle in the dependency graph since P
>       depends on p-stubs (scope:test) and p-stubs depends on P. See
>       https://stackoverflow.com/questions/10174542
>    - Create an independent "P - Tests" project, with P's stubs and tests.
>       - p-tests depends on P.
>       - Stubs, testing utilities, etc. go in p-tests/src/main/.
>       - P's tests go in p-tests/src/test/.
>       - D depends on p-tests with scope:test.
>       - This almost works but fails on #1: P's build succeeds when its
>       tests fail.
>       - This approach also seems to be fighting Maven and IDE tooling. For
>       example, NetBeans will automatically create p/src/test even
> though we never
>       intend to put anything there.
>
> My searches so far have not turned up any complete solutions to this
> problem. The maven-jar-plugin documentation has a section
> <
> https://maven.apache.org/plugins/maven-jar-plugin/examples/create-test-jar.html#The_preferred_way
> >
> that touches on this issue:
>
> The preferred way
>
> In order to let Maven resolve all test-scoped transitive dependencies you
> should create a separate project.
>
>
>    1. <project>
>    2.    <groupId>groupId</groupId>
>    3.     <artifactId>artifactId-tests</artifactId>
>    4.     <version>version</version>
>    5.   ...
>    6. </project>
>
>
>    - Move the sources files from src/test/java you want to share from the
>    original project to the src/main/java of this project. The same type of
>    movement counts for the resources as well of course.
>    - Move the required test-scoped dependencies and from the original
>    project to this project and remove the scope (i.e. changing it to the
>    compile-scope). And yes, that means that the junit dependency (or any
>    other testing framework dependency) gets the default scope too. You'll
>    probably need to add some project specific dependencies as well to let
> it
>    all compile again.
>
> Now you have your reusable *test-classes* and you can refer to it as you're
> used to...
>
> This is along the lines of the "P - Stubs" approach I suggested above, but
> it unfortunately cannot work since the stubs themselves depend on P (fails
> on #3 above).
>
> Is there a satisfying way to solve this problem? It seems to me like any
> one of the following changes would resolve the issue.
>
>    - Allow P to depend on a separate project p-stubs with scope:test, even
>    though p-stubs depends on P (instead of calling it a dependency cycle).
>    This means that the build order would be a bit awkward: P (compile) →
>    p-stubs (compile) → P (test).
>    - Allow P to indicate that its tests are in another project p-tests.
>    That way, `mvn install` in p/ would continue to p-tests/ and then fail
> P's
>    build if the tests in p-tests fail.
>    - Introduce a new "stubs" concept to the project model, adding a new
>    p/stubs directory for project P. A stubs-compile step would occur
> between
>    compile and test-compile. The stubs and tests of D could depend on P's
>    stubs (perhaps automatically by virtue of D's dependency on P).
>
> Maybe one of these—or a better alternative—is already possible? I feel like
> I must be missing something. Is something wrong with the way I'm
> structuring my projects? Does Maven already provide a way to achieve this
> out-of-the-box? Is there a plugin that provides something like the "stubs"
> functionality?
>
> Thanks!
> Brandon
>
> p.s. Sorry that my first message to the list is so long!
>

Reply via email to