Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot / JUnit, run all unit-tests for multiple profiles

I have a BaseTest class which consists of several tests. Each test shall be executed for EVERY profile I list.

I thought about using Parameterized values such as:

@RunWith(Parameterized.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
// @ActiveProfiles("h2-test") // <-- how to iterate over this?
public abstract class BaseTest {

@Autowired
private TestRepository test;

// to be used with Parameterized/Spring
private TestContextManager testContextManager;

public BaseTest(String profile) {
   System.setProperty("spring.profiles.active", profile);
   // TODO what now?
}

@Parameterized.Parameters
public static Collection<Object[]> data() {
  Collection<Object[]> params = new ArrayList<>();
  params.add(new Object[] {"h2-test" });
  params.add(new Object[] {"mysql-test" });
  return params;
}

@Before 
public void setUp() throws Exception {
  this.testContextManager = new TestContextManager(getClass());
  this.testContextManager.prepareTestInstance(this);
  // maybe I can spinup Spring here with my profile?
}

@Test
public void testRepository() {
  Assert.assertTrue(test.exists("foo"))
}

How would I tell Spring to run each test with these different profiles? In fact, each profile will talk to different datasources (in-memory h2, external mysql, external oracle, ..) so my repository/datasource has to be reinitialized.


I know that I can specify @ActiveProfiles(...) and I can even extend from BaseTest and override the ActiveProfile annotation. Although this will work, I only show a portion of my test-suite. Lots of my test-classes extend from BaseTest and I don't want to create several different profile-stubs for each class. Currently working, but ugly solution:

  • BaseTest (@ActiveProfiles("mysql"))
    • FooClassMySQL(annotation from BaseTest)
      • FooClassH2(@ActiveProfiles("h2"))
    • BarClassMySQL(annotation from BaseTest)
      • BarClassH2(@ActiveProfiles("h2"))

Thanks

like image 302
Frame91 Avatar asked Jul 19 '17 20:07

Frame91


2 Answers

For what it's worth:

My use case was to run a specific test class for multiple spring profiles, this is how I achieved it:

@SpringBootTest
abstract class BaseTest {
 @Test void doSomeTest() {... ARRANGE-ACT-ASSERT ...}
}

@ActiveProfiles("NextGen")
class NextGenTest extends BaseTest {}

@ActiveProfiles("Legacy")
class LegacyTest extends BaseTest {}
like image 169
Amith Kumar Avatar answered Sep 19 '22 13:09

Amith Kumar


If you use Maven you can actually specify active profile from command line (or env variable if needed):

mvn clean test -Dspring.profiles.active=h2-test

The approach with parameterized test may not work in this case, because profile has to be specified before Spring boots up its context. In this case when you run parameterized integration test the context will be already booted up before test runner starts running your test. Also JUnit's parameterized tests were invented for other reasons (running unit tests with different data series).

EDIT: Also one more thing - when you decide to use @RunWith(Parameterized.class) you wont be able to use different runner. In many cases (if not all if it comes to integration testing) you want to specify different runner, like SpringRunner.class - with parameterized test you wont be able to do it.

like image 20
Szymon Stepniak Avatar answered Sep 19 '22 13:09

Szymon Stepniak