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! >