Spring Boot / JUnit, run all unit-tests for multip

2019-06-16 10:53发布

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

2条回答
一纸荒年 Trace。
2楼-- · 2019-06-16 11:24

Spring profiles are not designed to work in this way.
In your case, each profile uses a specific datasource.
So each one requires a Spring Boot load to run tests with the expected datasource.

In fact, what you want to do is like making as many Maven build as Spring profiles that you want to test.

Besides, builds in local env should be as fast as possible.
Multiplying automated tests execution by DBMS implementation that requires a Spring Boot reload for each one will not help.

You should not need to specify @ActiveProfiles .

It looks rather like a task for a Continuous Integration tool where you could define a job that executes (sequentially or parallely) each Maven build by specifying a specific Spring Boot profile :

mvn clean test -Dspring.profiles.active=h2

mvn clean test -Dspring.profiles.active=mysql

etc...

You can also try to perform it in local by writing a script that performs the execution of the maven builds.
But as said, it will slowdown your local build and also complex it.

查看更多
▲ chillily
3楼-- · 2019-06-16 11:40

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.

查看更多
登录 后发表回答