6

As the host of Redis is different in local and CI, my @Tests can pass locally, they can't pass in CI.

Firstly, I tried to mock the RedisTemplate like this:

RedisTemplate redisTemplate = mock(RedisTemplate.class);
ValueOperations valueOperations = mock(ValueOperations.class);
when(redisTemplate.opsForValue()).thenReturn(valueOperations);
when(valueOperations.increment(anyString(), anyLong())).thenReturn(1L);
when(valueOperations.get("a@a.com")).thenReturn("1");

It did mocked RedisTemplate, but can't mock redisTemplate.opsForValue() and valueOperations.increment(...) ( I can't find reason )

Then, I wrote two profiles named application-ci-test.yml and applicaiton-test.yml, tried to active one of them based on system environment variable

I learnd from here that I can set active profile in this way:

@Configuration
public class MyWebApplicationInitializer 
  implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        servletContext.setInitParameter(
          "spring.profiles.active", "dev");
    }
}

and this way:

@Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");

But I don't know how to use them. The system variable can get by System.getenv(..). So now I want to know how to active profile based on the variable I get.

Jiaqi CHAI
  • 121
  • 1
  • 6
  • I think there's a few things here. To set a different profile in your CI environment, simply set an environment variable there. Your CI server should allow setting a custom environment variable. Don't set it in your application! – Balázs Németh Dec 21 '18 at 11:42

3 Answers3

6

I found a way to active corresponding profile based on system variable or property:

import org.springframework.test.context.ActiveProfilesResolver;

public class SpringActiveProfileResolver implements ActiveProfilesResolver {
    @Override
    public String[] resolve(Class<?> testClass) {
        final String isCITest = System.getEnv("isCITest");
        return new String[] { isCITest == null ? "test" : "ci-test" };
    }
} 

then use the parameter resolver in @ActiveProiles:

@ActiveProfiles(resolver = SpringActiveProfileResolver.class)

How to set environment variable is anther issue, and answers above have already answered it

Jiaqi CHAI
  • 121
  • 1
  • 6
3

Assuming your @Test methods are in a class with the @SpringBootTest annotation, you can use @ActiveProfiles to set the profile.

@SpringBootTest
@ActiveProfiles("someProfile")
pcoates
  • 2,102
  • 1
  • 9
  • 20
  • But the @Test methods need different profiles in different environments, cause the hosts of Redis is different in these two environments. – Jiaqi CHAI Dec 21 '18 at 11:59
  • Then you just need to set the spring.profiles.active environment property on the CI environment. Maybe post details of how you run the build on the CI environment (e.g. a Jenkins job running a gradle task). You need to set the profile there before the tests run. – pcoates Dec 21 '18 at 12:27
2

Use run parameters inside your CI job/script.

Depending how You start Your tests, You can for example do it with VM arguments

mvn test -Dspring.profiles.active=ci-test

or

java -jar -Dspring.profiles.active=ci-test

or whatever.

On the other hand you can use program arguments:

java -jar --spring.profiles.active=ci-test

One way or the other, providing active profile at start will activate property file of your choice.

If you want some specific piece of code (configuration class for example) to be run with specific profile only, annotate that piece of code with @Profile("ci-test")

Example:

@Configuration
@Profile("ci-test")
public class SomeConfiguration {
   //any configuration beans etc.
}

Following class will only be loaded when Your active profile will be "ci-test". So if You run Your app on Your CI server with one of the commands above, both property file named "ci-test" and this configuration class will get loaded.

It's also worth adding that in order for some code to run in ALL profiles EXCEPT specified, you can negate the name inside profile annotation like: @Profile("!ci-test").

Code annotated like that will run with all profiles (including default) except "ci-test".

patrykos91
  • 3,506
  • 2
  • 24
  • 30