3

I am working with:

  • Spring Framework 4.3.10
  • JUnit 4.12
  • Gradle 4.3.1

I have these two test classes

@Transactional
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class})
@ActiveProfiles(resolver=TestJdbcActiveProfilesResolver.class)
@TestExecutionListeners(listeners={LoggingTestExecutionListener.class}, mergeMode=MergeMode.MERGE_WITH_DEFAULTS)
public class PersonaServiceImplJdbcTest {


@Transactional
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class})
@ActiveProfiles(resolver=TestHibernateActiveProfilesResolver.class)
@TestExecutionListeners(listeners={LoggingTestExecutionListener.class}, mergeMode=MergeMode.MERGE_WITH_DEFAULTS)
public class PersonaServiceImplHibernateTest {

The code about the @Test methods are the same for both Test classes, breaking the DRY principle, the unique difference between these two test classes is the jdbc and Hibernate profiles working together with other such as development, mysql, it internally through each TestXXXActiveProfilesResolver class variation.

Until here I have 2 test classes, breaking the DRY principle, thinking in hierarchy I am going to get 3.

How (if is possible) use one Test class where for each interaction executes two (or more) sets of profiles such as:

  • jdbc,development,mysql
  • Hibernate,development,mysql

I already have read:

But I want avoid use commands either through Maven or Gradle, it to keep the control through the TestXXXActiveProfilesResolver classes.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
  • If all you're after is to share the test method code, either create a delegate they both refer to, or add a common base class with the code for sharing. – Taylor Dec 14 '17 at 15:43
  • I thought the same about hierarchy, but I have the following in consideration https://www.petrikainulainen.net/programming/unit-testing/3-reasons-why-we-should-not-use-inheritance-in-our-tests/ – Manuel Jordan Dec 14 '17 at 15:46
  • Ok, use composition instead. – Taylor Dec 14 '17 at 15:48

1 Answers1

5

For JUnit 4 finally I did the following (scroll down):

@Transactional
@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class})
//@ActiveProfiles() ... disable
@TestExecutionListeners(listeners={LoggingTestExecutionListener.class}, mergeMode=MergeMode.MERGE_WITH_DEFAULTS)
public abstract class PersonaServiceImplTest {

   ...

   @Autowired
   private Environment environment;

   @Before
   public void setup(){
    logger.info("Profiles: {}", Arrays.toString(environment.getActiveProfiles()));
   }

   //@Test disable
   public void someTest(){

     assertThat(...)

   }

    @ActiveProfiles(resolver=TestJdbcActiveProfilesResolver.class)
    public static class ForJdbc extends PersonaServiceImplTest {

        public ForJdbc(Persona persona){
            super(persona);
        }

        @Test
        @Override
        @Sql(scripts={"classpath:/.../script.sql"})//when be necessary
        public void someTest()(){
            super.someTest()();
        }

      }

    @ActiveProfiles(resolver=TestHibernateActiveProfilesResolver.class)
    public static class ForHibernate extends PersonaServiceImplTest {

        public ForHibernate(Persona persona){
            super(persona);
        }

        @Test
        @Override
        @Sql(scripts={"classpath:/.../script.sql"})//when be necessary
        public void someTest()(){
            super.someTest()();
        }

        ...

      }

   }

Observations:

  • The outer class must be abstract
  • The outer class must have no @ActiveProfiles declared
  • The outer class has the methods to be tested, each one must have no the @Test declared
  • Environment is optional but is useful to let know the profiles activated for each static nested class, it through the common method annotated with @Before
  • Each static nested class must be public
  • Each static nested class must extends the outer class
  • Each static nested class must have @ActiveProfiles
  • Each static nested class overrides each test method, just to use super to call the respective overridden method
  • Each static nested class, for each test overridden method, it must have the @Test.
  • @Sql can't be reused, it must be declared for each overridden method
Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158