Skip to content

Instantly share code, notes, and snippets.

@rponte
Last active February 7, 2024 02:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rponte/4f21012d15e4fa6d24be78b7fb434624 to your computer and use it in GitHub Desktop.
Save rponte/4f21012d15e4fa6d24be78b7fb434624 to your computer and use it in GitHub Desktop.
Mocking Spring Boot Environment during integration tests
package br.com.rponte.base.spring.config.env;
import org.junit.rules.ExternalResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.mock.env.MockPropertySource;
import org.springframework.stereotype.Component;
/**
* https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/ConfigurableEnvironment.html
*/
@Component
public class MockEnvironmentRule extends ExternalResource {
private static final String JUNIT_RULE_PROPERTY_SOURCE_NAME = "_junitRulePropertySource";
@Autowired
private ConfigurableEnvironment environment;
private MockPropertySource mockEnvVars;
@Override
protected void before() throws Throwable {
// creates a temporary property source and configures it into Spring environment with highest precedence
mockEnvVars = new MockPropertySource(JUNIT_RULE_PROPERTY_SOURCE_NAME);
environment.getPropertySources().addFirst(mockEnvVars);
}
@Override
protected void after() {
// removes the temporary property source
environment.getPropertySources().remove(mockEnvVars.getName());
}
/**
* Set the given property with highest search priority
*/
public MockEnvironmentRule setProperty(String key, String value) {
mockEnvVars.setProperty(key, value);
return this;
}
}
package br.com.rponte.app.web.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import br.com.mdias.test.config.SpringConfigTestCase;
import br.com.mdias.test.config.env.MockEnvironmentRule;
@WebMvcTest
public class ProdutoControllerTest extends SpringWebIntegrationTestCase {
@Rule
@Autowired
public MockEnvironmentRule environment;
@Test
public void deveObterVersaoAtualDoSistema() throws Exception {
// cenário
environment.setProperty("app.version", "2.3.7_91");
// ação e validação
mvc.perform(get("/app/info")
.with(loggedInUser()))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("version").value("2.3.7_91"))
;
}
@Test
public void deveObterVersaoPadrao_quandoNaoHouverVersaoNoSistema() throws Exception {
// ação e validação
mvc.perform(get("/app/info")
.with(loggedInUser()))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("version").value("1.0.0_00"))
;
}
}
@rponte
Copy link
Author

rponte commented Aug 2, 2018

Another possible solution could be using ApplicationContextInitializer like this one:

/**
 * http://blog.jamesdbloom.com/UsingPropertySourceAndEnvironment.html
 */
public class MockEnvironmentApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

	@Override
	public void initialize(ConfigurableApplicationContext context) {
		MockEnvironment mockEnvironment = new MockEnvironment();
		mockEnvironment.merge(context.getEnvironment());
		
		context.setEnvironment(mockEnvironment);
	}
}

And configuring it in the test classes:

// ...
@ContextConfiguration(classes = { ... }, initializers = { MockEnvironmentApplicationContextInitializer.class }
public class ProductController  {
    // ...
}

But I'm not totally sure if this is the best solution.

@rponte
Copy link
Author

rponte commented Aug 2, 2018

@rponte
Copy link
Author

rponte commented Jan 2, 2019

If I'm not wrong, in new versions of Spring Boot I can use an annotation to change properties for each method, similar to inline properties API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment