Best Practice for distributing test utilities?

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Best Practice for distributing test utilities?

Andreas Sewe-2
Hi,

I am struggling to figure out what the Maven Way is for distributing
test utils.

Say I have a project "foo" along with some unit tests for it. Moreover,
I have some utilities that help in testing "foo" (e.g., test data
builders or test fixtures). These utilities are used by the unit tests
for "foo", but may also be useful to projects depending on "foo" (e.g.,
a FooTestDataBuilder that produces Foo instances could also be used in
the tests of a dependent project "bar").

The question is where to place these test utilities and how to depend on
them.

1. I could follow the "guide to using attached tests" [1], place the
test utilizes in foo/src/test/java, and attach the test-jar to "foo".
Then, a dependent project "bar" could depend on the test-jar in its test
scope. Alas, as the test scope is not transitive, I would need to
declare all test-dependencies of "foo" again in "bar", even though I may
not even use them directly (e.g., if the FooTestDataBuilder uses them
only internally).

2. I could split "foo" into three projects: "foo", "foo-test-utils", and
"foo-tests", with the latter depending on both "foo-test-utils" and
"foo-tests". A project "bar" would then simply depend on "foo" in
compile scope and "foo-test-utils" in test scope. This would make all
dependencies explicit, but would result in some oddities, e.g.,
foo-tests/src/main/java being empty, as all tests need to be placed in
tests/src/test/java to be picked up by Surefire.

3. I could split "foo" into just two projects, "foo" and "foo-testing".
foo-testing/src/main/java would the contain the test utilities for
"foo", whereas foo-testing/src/test/java would contain the actual tests.
This is again somewhat odd, as the tests in foo-testing/src/test/java
are not testing "foo-testing" but "foo".

4. Option 4 is the most natural way, but unfortunately it doesn't work,
because it introduces a cyclic dependency: Have "foo" and
"foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".

Am I missing something? In particular, why is [1] apparently the
recommended approach, even though it requires you to duplicate
dependency information?

Any suggestions are greatly appreciated.

Best wishes,

Andreas

[1] <https://maven.apache.org/guides/mini/guide-attached-tests.html>


signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Anders Hammar
I'd say option 4 is the way to go. But you need to solve the circular
dependency problem. One way is to have a third api project/module, which
foo-test-utils have a compile time dependency on. Here you could use the
Service Provider Interface pattern.

/Anders

On Thu, Mar 12, 2020 at 2:55 PM Andreas Sewe <
[hidden email]> wrote:

> Hi,
>
> I am struggling to figure out what the Maven Way is for distributing
> test utils.
>
> Say I have a project "foo" along with some unit tests for it. Moreover,
> I have some utilities that help in testing "foo" (e.g., test data
> builders or test fixtures). These utilities are used by the unit tests
> for "foo", but may also be useful to projects depending on "foo" (e.g.,
> a FooTestDataBuilder that produces Foo instances could also be used in
> the tests of a dependent project "bar").
>
> The question is where to place these test utilities and how to depend on
> them.
>
> 1. I could follow the "guide to using attached tests" [1], place the
> test utilizes in foo/src/test/java, and attach the test-jar to "foo".
> Then, a dependent project "bar" could depend on the test-jar in its test
> scope. Alas, as the test scope is not transitive, I would need to
> declare all test-dependencies of "foo" again in "bar", even though I may
> not even use them directly (e.g., if the FooTestDataBuilder uses them
> only internally).
>
> 2. I could split "foo" into three projects: "foo", "foo-test-utils", and
> "foo-tests", with the latter depending on both "foo-test-utils" and
> "foo-tests". A project "bar" would then simply depend on "foo" in
> compile scope and "foo-test-utils" in test scope. This would make all
> dependencies explicit, but would result in some oddities, e.g.,
> foo-tests/src/main/java being empty, as all tests need to be placed in
> tests/src/test/java to be picked up by Surefire.
>
> 3. I could split "foo" into just two projects, "foo" and "foo-testing".
> foo-testing/src/main/java would the contain the test utilities for
> "foo", whereas foo-testing/src/test/java would contain the actual tests.
> This is again somewhat odd, as the tests in foo-testing/src/test/java
> are not testing "foo-testing" but "foo".
>
> 4. Option 4 is the most natural way, but unfortunately it doesn't work,
> because it introduces a cyclic dependency: Have "foo" and
> "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".
>
> Am I missing something? In particular, why is [1] apparently the
> recommended approach, even though it requires you to duplicate
> dependency information?
>
> Any suggestions are greatly appreciated.
>
> Best wishes,
>
> Andreas
>
> [1] <https://maven.apache.org/guides/mini/guide-attached-tests.html>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Mark Prins
In reply to this post by Andreas Sewe-2
refactor foo to a multimodule one with the test utilities as an artifact
and one with the code + tests for original foo, you can then depend on
the test module with scope test in the main module and keep everything
in source repo making it easy to stay in sync

On 12-03-2020 14:55, Andreas Sewe wrote:

> Hi,
>
> I am struggling to figure out what the Maven Way is for distributing
> test utils.
>
> Say I have a project "foo" along with some unit tests for it. Moreover,
> I have some utilities that help in testing "foo" (e.g., test data
> builders or test fixtures). These utilities are used by the unit tests
> for "foo", but may also be useful to projects depending on "foo" (e.g.,
> a FooTestDataBuilder that produces Foo instances could also be used in
> the tests of a dependent project "bar").
>
> The question is where to place these test utilities and how to depend on
> them.
>
> 1. I could follow the "guide to using attached tests" [1], place the
> test utilizes in foo/src/test/java, and attach the test-jar to "foo".
> Then, a dependent project "bar" could depend on the test-jar in its test
> scope. Alas, as the test scope is not transitive, I would need to
> declare all test-dependencies of "foo" again in "bar", even though I may
> not even use them directly (e.g., if the FooTestDataBuilder uses them
> only internally).
>
> 2. I could split "foo" into three projects: "foo", "foo-test-utils", and
> "foo-tests", with the latter depending on both "foo-test-utils" and
> "foo-tests". A project "bar" would then simply depend on "foo" in
> compile scope and "foo-test-utils" in test scope. This would make all
> dependencies explicit, but would result in some oddities, e.g.,
> foo-tests/src/main/java being empty, as all tests need to be placed in
> tests/src/test/java to be picked up by Surefire.
>
> 3. I could split "foo" into just two projects, "foo" and "foo-testing".
> foo-testing/src/main/java would the contain the test utilities for
> "foo", whereas foo-testing/src/test/java would contain the actual tests.
> This is again somewhat odd, as the tests in foo-testing/src/test/java
> are not testing "foo-testing" but "foo".
>
> 4. Option 4 is the most natural way, but unfortunately it doesn't work,
> because it introduces a cyclic dependency: Have "foo" and
> "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".
>
> Am I missing something? In particular, why is [1] apparently the
> recommended approach, even though it requires you to duplicate
> dependency information?
>
> Any suggestions are greatly appreciated.
>
> Best wishes,
>
> Andreas
>
> [1] <https://maven.apache.org/guides/mini/guide-attached-tests.html>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Andreas Sewe-2
In reply to this post by Anders Hammar
Anders Hammar wrote:
> I'd say option 4 is the way to go. But you need to solve the circular
> dependency problem. One way is to have a third api project/module, which
> foo-test-utils have a compile time dependency on. Here you could use the
> Service Provider Interface pattern.

>> 4. Option 4 is the most natural way, but unfortunately it doesn't work,
>> because it introduces a cyclic dependency: Have "foo" and
>> "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".

I don't think adding a SPI can be used to make option 4 work.

Simplest case:

- Project "foo" contains a class Foo.

- Project "foo-test-utils" contains a class FooTestDataBuilder, whose
code obviously refers to Foo. Hence, "foo-test-utils" needs a
compile-scoped dependency on "foo"

- Tests in project "foo" would like to use the FooTestDataBuilder.

Even I add a IFooTestDataBuilder interface, I could get the tests of
project "foo" to *compile*, but to actually *run* them, I would need a
FooTestDataBuilder -- which is defined in the *dependent* project
"foo-test-utils".

But maybe I am missing something.

Best wishes,

Andreas


signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Andreas Sewe-2
In reply to this post by Mark Prins
Mark Prins wrote:
> refactor foo to a multimodule one with the test utilities as an artifact
> and one with the code + tests for original foo, you can then depend on
> the test module with scope test in the main module and keep everything
> in source repo making it easy to stay in sync

Grouping everything below an aggregator project is certainly a good
idea, but I doubt having code + tests in the same module will work. If I
understand you correctly, you describe the following module structure
below the "foo" aggregator:

- Project "foo-main" contains a class Foo.

- Project "foo-test-utils" contains a class FooTestDataBuilder, whose
code obviously refers to Foo. Hence, "foo-test-utils" needs a
compile-scoped dependency on "foo".

- Tests in project "foo-main" would like to use the FooTestDataBuilder
and have a test-scoped dependency on "foo-test-utils".

But that leaves me with a cyclic dependency:

  foo-main  --test->  foo-test-utils  --compile->  foo-main.

Or am I missing something?

Best wishes,

Andreas


signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Anders Hammar
In reply to this post by Andreas Sewe-2
You need to remove the compile time dependency from foo-test-utils to foo.
Obviously you will have a runtime dependency, but that's ok. One simple way
is to use reflection in foo-test-utils when instantiating the Foo object.
Not pretty, but a simple solution. There are more elegant solutions but
they could be overkill in this case.

/Anders

On Fri, Mar 13, 2020 at 10:29 AM Andreas Sewe <
[hidden email]> wrote:

> Anders Hammar wrote:
> > I'd say option 4 is the way to go. But you need to solve the circular
> > dependency problem. One way is to have a third api project/module, which
> > foo-test-utils have a compile time dependency on. Here you could use the
> > Service Provider Interface pattern.
>
> >> 4. Option 4 is the most natural way, but unfortunately it doesn't work,
> >> because it introduces a cyclic dependency: Have "foo" and
> >> "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".
>
> I don't think adding a SPI can be used to make option 4 work.
>
> Simplest case:
>
> - Project "foo" contains a class Foo.
>
> - Project "foo-test-utils" contains a class FooTestDataBuilder, whose
> code obviously refers to Foo. Hence, "foo-test-utils" needs a
> compile-scoped dependency on "foo"
>
> - Tests in project "foo" would like to use the FooTestDataBuilder.
>
> Even I add a IFooTestDataBuilder interface, I could get the tests of
> project "foo" to *compile*, but to actually *run* them, I would need a
> FooTestDataBuilder -- which is defined in the *dependent* project
> "foo-test-utils".
>
> But maybe I am missing something.
>
> Best wishes,
>
> Andreas
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Zak Mc Kracken-2
In reply to this post by Andreas Sewe-2
On 12/03/2020 13:55, Andreas Sewe wrote:

If the test utilities are simple enough and are somehow specific to foo,
I would put them into foo, under src/main/java, in a package like
com.foo.testing. If they are more general, so that they could be used to
write tests for some other package not related to foo, I would create a
test-utils module. For instance, a utility to verify that an SQL string
parameter yields a given result parameter would go into such a module.

If the test utils so complex that foo would become too big and would
drag too many not-often-used dependencies, but they're foo-specific, I
would create the module foo-test-utils and both foo and foo-testing
would depend on it. This is similar to creating test-utils.

Option 3 creates a circular dependency and it's not to clean anyway
(even if you had a way to remove the circularity from the technical
point of view, it would remain at conceptual level). Attaching tests
seems to be less clear and forces a dependant to link all the tests just
to be able to include some utility. I happened to do it only for already
existing and hard-to-refactor projects, and only for the purpose making
the dependant extract some common files inside test/resources.

Hope it helps,
Marco

> Hi,
>
> I am struggling to figure out what the Maven Way is for distributing
> test utils.
>
> Say I have a project "foo" along with some unit tests for it. Moreover,
> I have some utilities that help in testing "foo" (e.g., test data
> builders or test fixtures). These utilities are used by the unit tests
> for "foo", but may also be useful to projects depending on "foo" (e.g.,
> a FooTestDataBuilder that produces Foo instances could also be used in
> the tests of a dependent project "bar").
>
> The question is where to place these test utilities and how to depend on
> them.
>
> 1. I could follow the "guide to using attached tests" [1], place the
> test utilizes in foo/src/test/java, and attach the test-jar to "foo".
> Then, a dependent project "bar" could depend on the test-jar in its test
> scope. Alas, as the test scope is not transitive, I would need to
> declare all test-dependencies of "foo" again in "bar", even though I may
> not even use them directly (e.g., if the FooTestDataBuilder uses them
> only internally).
>
> 2. I could split "foo" into three projects: "foo", "foo-test-utils", and
> "foo-tests", with the latter depending on both "foo-test-utils" and
> "foo-tests". A project "bar" would then simply depend on "foo" in
> compile scope and "foo-test-utils" in test scope. This would make all
> dependencies explicit, but would result in some oddities, e.g.,
> foo-tests/src/main/java being empty, as all tests need to be placed in
> tests/src/test/java to be picked up by Surefire.
>
> 3. I could split "foo" into just two projects, "foo" and "foo-testing".
> foo-testing/src/main/java would the contain the test utilities for
> "foo", whereas foo-testing/src/test/java would contain the actual tests.
> This is again somewhat odd, as the tests in foo-testing/src/test/java
> are not testing "foo-testing" but "foo".
>
> 4. Option 4 is the most natural way, but unfortunately it doesn't work,
> because it introduces a cyclic dependency: Have "foo" and
> "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".
>
> Am I missing something? In particular, why is [1] apparently the
> recommended approach, even though it requires you to duplicate
> dependency information?
>
> Any suggestions are greatly appreciated.
>
> Best wishes,
>
> Andreas
>
> [1] <https://maven.apache.org/guides/mini/guide-attached-tests.html>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Nick_S
Put the testutils and the tests in the same project as foo in src/test/java
and make the tests package private (JUnit Jupiter). Other projects can
depend on the test artifact of foo and only use the test-utils.

Hth,

Nick Stolwijk

~~~ Try to leave this world a little better than you found it and, when
your turn comes to die, you can die happy in feeling that at any rate you
have not wasted your time but have done your best ~~~

Lord Baden-Powell


On Fri, Mar 13, 2020 at 12:01 PM Zak Mc Kracken <[hidden email]>
wrote:

> On 12/03/2020 13:55, Andreas Sewe wrote:
>
> If the test utilities are simple enough and are somehow specific to foo,
> I would put them into foo, under src/main/java, in a package like
> com.foo.testing. If they are more general, so that they could be used to
> write tests for some other package not related to foo, I would create a
> test-utils module. For instance, a utility to verify that an SQL string
> parameter yields a given result parameter would go into such a module.
>
> If the test utils so complex that foo would become too big and would
> drag too many not-often-used dependencies, but they're foo-specific, I
> would create the module foo-test-utils and both foo and foo-testing
> would depend on it. This is similar to creating test-utils.
>
> Option 3 creates a circular dependency and it's not to clean anyway
> (even if you had a way to remove the circularity from the technical
> point of view, it would remain at conceptual level). Attaching tests
> seems to be less clear and forces a dependant to link all the tests just
> to be able to include some utility. I happened to do it only for already
> existing and hard-to-refactor projects, and only for the purpose making
> the dependant extract some common files inside test/resources.
>
> Hope it helps,
> Marco
>
> > Hi,
> >
> > I am struggling to figure out what the Maven Way is for distributing
> > test utils.
> >
> > Say I have a project "foo" along with some unit tests for it. Moreover,
> > I have some utilities that help in testing "foo" (e.g., test data
> > builders or test fixtures). These utilities are used by the unit tests
> > for "foo", but may also be useful to projects depending on "foo" (e.g.,
> > a FooTestDataBuilder that produces Foo instances could also be used in
> > the tests of a dependent project "bar").
> >
> > The question is where to place these test utilities and how to depend on
> > them.
> >
> > 1. I could follow the "guide to using attached tests" [1], place the
> > test utilizes in foo/src/test/java, and attach the test-jar to "foo".
> > Then, a dependent project "bar" could depend on the test-jar in its test
> > scope. Alas, as the test scope is not transitive, I would need to
> > declare all test-dependencies of "foo" again in "bar", even though I may
> > not even use them directly (e.g., if the FooTestDataBuilder uses them
> > only internally).
> >
> > 2. I could split "foo" into three projects: "foo", "foo-test-utils", and
> > "foo-tests", with the latter depending on both "foo-test-utils" and
> > "foo-tests". A project "bar" would then simply depend on "foo" in
> > compile scope and "foo-test-utils" in test scope. This would make all
> > dependencies explicit, but would result in some oddities, e.g.,
> > foo-tests/src/main/java being empty, as all tests need to be placed in
> > tests/src/test/java to be picked up by Surefire.
> >
> > 3. I could split "foo" into just two projects, "foo" and "foo-testing".
> > foo-testing/src/main/java would the contain the test utilities for
> > "foo", whereas foo-testing/src/test/java would contain the actual tests.
> > This is again somewhat odd, as the tests in foo-testing/src/test/java
> > are not testing "foo-testing" but "foo".
> >
> > 4. Option 4 is the most natural way, but unfortunately it doesn't work,
> > because it introduces a cyclic dependency: Have "foo" and
> > "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".
> >
> > Am I missing something? In particular, why is [1] apparently the
> > recommended approach, even though it requires you to duplicate
> > dependency information?
> >
> > Any suggestions are greatly appreciated.
> >
> > Best wishes,
> >
> > Andreas
> >
> > [1] <https://maven.apache.org/guides/mini/guide-attached-tests.html>
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Best Practice for distributing test utilities?

Matthieu BROUILLARD-3
Hi Andreas,

In your use case I would keep everything in the same foo project but I
would generate a kind of 'testutils' jar.

From what I understood your project structure is a bit like

foo
   src/main/java
   src/test/java
      com.yourcompany.tests.utils
      com.yourcompany.tests.yourtests


Then using `maven-jar-plugin` (see [1]) I would generate a dedicated jar
with classifier 'testutils' using only tests classes of
com.yourcompany.tests.utils package (filter what you need) resulting in
producing/publishing an additional foo-X.Y.Z-testutils.jar

Then client projects would need to use 2 dependencies

<dependency>
    <artifactId>foo</artifactId>
    <version>X.Y.Z</version>
</dependency>
<dependency>
    <artifactId>foo</artifactId>
    <version>X.Y.Z</version>
    <classifier>testutils</ classifier>
    <type>jar</type>
    <scope>test</scope>
</dependency>

Hope it can help.

Matthieu

[1] :
https://maven.apache.org/plugins/maven-jar-plugin/examples/attached-jar.html


On Fri, Mar 13, 2020 at 1:49 PM Nick Stolwijk <[hidden email]>
wrote:

> Put the testutils and the tests in the same project as foo in src/test/java
> and make the tests package private (JUnit Jupiter). Other projects can
> depend on the test artifact of foo and only use the test-utils.
>
> Hth,
>
> Nick Stolwijk
>
> ~~~ Try to leave this world a little better than you found it and, when
> your turn comes to die, you can die happy in feeling that at any rate you
> have not wasted your time but have done your best ~~~
>
> Lord Baden-Powell
>
>
> On Fri, Mar 13, 2020 at 12:01 PM Zak Mc Kracken <[hidden email]
> >
> wrote:
>
> > On 12/03/2020 13:55, Andreas Sewe wrote:
> >
> > If the test utilities are simple enough and are somehow specific to foo,
> > I would put them into foo, under src/main/java, in a package like
> > com.foo.testing. If they are more general, so that they could be used to
> > write tests for some other package not related to foo, I would create a
> > test-utils module. For instance, a utility to verify that an SQL string
> > parameter yields a given result parameter would go into such a module.
> >
> > If the test utils so complex that foo would become too big and would
> > drag too many not-often-used dependencies, but they're foo-specific, I
> > would create the module foo-test-utils and both foo and foo-testing
> > would depend on it. This is similar to creating test-utils.
> >
> > Option 3 creates a circular dependency and it's not to clean anyway
> > (even if you had a way to remove the circularity from the technical
> > point of view, it would remain at conceptual level). Attaching tests
> > seems to be less clear and forces a dependant to link all the tests just
> > to be able to include some utility. I happened to do it only for already
> > existing and hard-to-refactor projects, and only for the purpose making
> > the dependant extract some common files inside test/resources.
> >
> > Hope it helps,
> > Marco
> >
> > > Hi,
> > >
> > > I am struggling to figure out what the Maven Way is for distributing
> > > test utils.
> > >
> > > Say I have a project "foo" along with some unit tests for it. Moreover,
> > > I have some utilities that help in testing "foo" (e.g., test data
> > > builders or test fixtures). These utilities are used by the unit tests
> > > for "foo", but may also be useful to projects depending on "foo" (e.g.,
> > > a FooTestDataBuilder that produces Foo instances could also be used in
> > > the tests of a dependent project "bar").
> > >
> > > The question is where to place these test utilities and how to depend
> on
> > > them.
> > >
> > > 1. I could follow the "guide to using attached tests" [1], place the
> > > test utilizes in foo/src/test/java, and attach the test-jar to "foo".
> > > Then, a dependent project "bar" could depend on the test-jar in its
> test
> > > scope. Alas, as the test scope is not transitive, I would need to
> > > declare all test-dependencies of "foo" again in "bar", even though I
> may
> > > not even use them directly (e.g., if the FooTestDataBuilder uses them
> > > only internally).
> > >
> > > 2. I could split "foo" into three projects: "foo", "foo-test-utils",
> and
> > > "foo-tests", with the latter depending on both "foo-test-utils" and
> > > "foo-tests". A project "bar" would then simply depend on "foo" in
> > > compile scope and "foo-test-utils" in test scope. This would make all
> > > dependencies explicit, but would result in some oddities, e.g.,
> > > foo-tests/src/main/java being empty, as all tests need to be placed in
> > > tests/src/test/java to be picked up by Surefire.
> > >
> > > 3. I could split "foo" into just two projects, "foo" and "foo-testing".
> > > foo-testing/src/main/java would the contain the test utilities for
> > > "foo", whereas foo-testing/src/test/java would contain the actual
> tests.
> > > This is again somewhat odd, as the tests in foo-testing/src/test/java
> > > are not testing "foo-testing" but "foo".
> > >
> > > 4. Option 4 is the most natural way, but unfortunately it doesn't work,
> > > because it introduces a cyclic dependency: Have "foo" and
> > > "foo-test-utils" and let the tests of "foo" depend on "foo-test-utils".
> > >
> > > Am I missing something? In particular, why is [1] apparently the
> > > recommended approach, even though it requires you to duplicate
> > > dependency information?
> > >
> > > Any suggestions are greatly appreciated.
> > >
> > > Best wishes,
> > >
> > > Andreas
> > >
> > > [1] <https://maven.apache.org/guides/mini/guide-attached-tests.html>
> > >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [hidden email]
> > For additional commands, e-mail: [hidden email]
> >
> >
>