Como definir a variável de ambiente ou propriedade do sistema em testes de primavera?

93

Gostaria de escrever alguns testes que verificam a configuração XML Spring de um WAR implantado. Infelizmente, alguns beans requerem que algumas variáveis ​​de ambiente ou propriedades do sistema sejam definidas. Como posso definir uma variável de ambiente antes que os beans Spring sejam inicializados ao usar o estilo de teste conveniente com @ContextConfiguration?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext { ... }

Se eu configurar o contexto do aplicativo com anotações, não vejo um gancho onde posso fazer algo antes que o contexto de primavera seja inicializado.

Hans-Peter Störr
fonte

Respostas:

127

Você pode inicializar a propriedade System em um inicializador estático:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext {

    static {
        System.setProperty("myproperty", "foo");
    }

}

O código do inicializador estático será executado antes que o contexto do aplicativo spring seja inicializado.

Jimmy Praet
fonte
14
Eu tola - OK, isso funcionaria. Melhor ainda: provavelmente um @BeforeClassmétodo para definir a propriedade do sistema e um @AfterClassmétodo para removê-la também funcionaria e limparia depois de si mesmo. (Não tentei, no entanto.)
Hans-Peter Störr
1
Tentei @BeforeClass - e funcionou bem para definir as propriedades do sistema antes que outras propriedades fossem definidas na instância de teste
wbdarby
Obrigado por isso. A coisa estática não funcionou, mas um pequeno método com @BeforeClass funcionou!
Midhun Agnihotram
Este mecanismo não funciona se alterar a propriedade do arquivo de configuração Log4j2. Parece que o Spring de qualquer maneira está sendo carregado (e, portanto, logando incorretamente) antes daquele pedaço de código estático.
lucasvc
86

A maneira certa de fazer isso, a partir do Spring 4.1, é usar uma @TestPropertySourceanotação.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
@TestPropertySource(properties = {"myproperty = foo"})
public class TestWarSpringContext {
    ...    
}

Consulte @TestPropertySource nos documentos e Javadocs do Spring .

Raman
fonte
2
Essa anotação também suporta um caminho de arquivo de propriedades.
MigDus
2
Eu poderia mudar o rótulo do cliente Spring Cloud Config durante os testes usando@TestPropertySource(properties={"spring.cloud.config.label=feature/branch"})
Marcello de Sales
4
Boa resposta, mas infelizmente não funcionou para mim, usando o Spring 4.2.9, a propriedade estava sempre vazia. Apenas o bloco estático funcionou ... Funcionou para propriedades do aplicativo, mas não para propriedades do sistema.
Gregor
Primeiro vi e experimentei a versão estática (que funcionou), mas esta Anotação é ainda mais limpa e muito mais preferível (para mim, porque também funciona muito bem).
BAERUS
3
Isso fornece uma Environmentpropriedade, que é diferente de uma "variável de ambiente".
OrangeDog
11

Também é possível usar um ApplicationContextInitializer de teste para inicializar uma propriedade do sistema:

public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext)
    {
        System.setProperty("myproperty", "value");
    }
}

e, em seguida, configure-o na classe de teste, além dos locais do arquivo de configuração de contexto do Spring:

@ContextConfiguration(initializers = TestApplicationContextInitializer.class, locations = "classpath:whereever/context.xml", ...)
@RunWith(SpringJUnit4ClassRunner.class)
public class SomeTest
{
...
}

Desta forma, a duplicação de código pode ser evitada se uma determinada propriedade do sistema deve ser definida para todos os testes de unidade.

anre
fonte
Isso também funciona perfeitamente com Spring Boot 2.xe Junit 5.x (usando @SpringBootTestou qualquer uma das anotações de
divisão
10

Todas as respostas aqui atualmente falam apenas sobre as propriedades do sistema, que são diferentes das variáveis ​​de ambiente que são mais complexas de definir, esp. para testes. Felizmente, a classe abaixo pode ser usada para isso e a documentação da classe tem bons exemplos

EnvironmentVariables.html

Um exemplo rápido dos documentos, modificado para funcionar com @SpringBootTest

@SpringBootTest
public class EnvironmentVariablesTest {
   @ClassRule
   public final EnvironmentVariables environmentVariables = new EnvironmentVariables().set("name", "value");

   @Test
   public void test() {
     assertEquals("value", System.getenv("name"));
   }
 }
Harish Gokavarapu
fonte
As regras de EnvironmentVariables são parte de uma biblioteca de terceiros, usam reflexão hacky para alterar os valores armazenados em cache do ambiente na memória JVM e nem mesmo as variáveis ​​de ambiente reais. Portanto, não gostaria de usá-lo ou recomendar a ninguém que o fizesse.
Cristão
4

Se você deseja que suas variáveis ​​sejam válidas para todos os testes, você pode ter um application.propertiesarquivo no diretório de recursos de teste (por padrão src/test/resources:) que será semelhante a este:

MYPROPERTY=foo

Isso será então carregado e usado, a menos que você tenha definições por meio de @TestPropertySourceou um método semelhante - a ordem exata em que as propriedades são carregadas pode ser encontrada na documentação do Spring, capítulo 24. Configuração externalizada .

blalasaadri
fonte
2

Você pode definir as propriedades do sistema como argumentos VM.

Se o seu projeto for um projeto maven, você pode executar o seguinte comando enquanto executa a classe de teste:

mvn test -Dapp.url="https://stackoverflow.com"

Classe de teste:

public class AppTest  {
@Test
public void testUrl() {
    System.out.println(System.getProperty("app.url"));
    }
}

Se você deseja executar uma classe de teste individual ou método no eclipse:

1) Vá para Executar -> Executar configuração

2) No lado esquerdo, selecione sua classe de teste na seção Junit.

3) faça o seguinte:

insira a descrição da imagem aqui

Joby Wilson Mathews
fonte
2

Para testes de unidade, a variável de sistema ainda não é instanciada quando eu faço "mvn clean install" porque não há servidor executando o aplicativo. Portanto, para definir as propriedades do sistema, preciso fazer isso em pom.xml. Igual a:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.21.0</version>
    <configuration>
        <systemPropertyVariables>
            <propertyName>propertyValue</propertyName>
            <MY_ENV_VAR>newValue</MY_ENV_VAR>
            <ENV_TARGET>olqa</ENV_TARGET>
            <buildDirectory>${project.build.directory}</buildDirectory>
        </systemPropertyVariables>
    </configuration>
</plugin>
Gene
fonte