Substituir configurações padrão de application.properties do Spring-Boot no Junit Test

198

Eu tenho um aplicativo Spring-Boot em que as propriedades padrão são definidas em um application.propertiesarquivo no caminho de classe (src / main / resources / application.properties).

Gostaria de substituir algumas configurações padrão no meu teste JUnit por propriedades declaradas em um test.propertiesarquivo (src / test / resources / test.properties)

Normalmente, tenho uma classe de configuração dedicada para meus testes Junit, por exemplo

package foo.bar.test;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

}

Primeiro pensei que o uso @PropertySource("classpath:test.properties")na classe TestConfig faria o truque, mas essas propriedades não substituirão as configurações de application.properties (consulte o Documento de Referência do Spring-Boot - 23. Configuração Externalizada ).

Então eu tentei usar -Dspring.config.location=classpath:test.propertiesao invocar o teste. Isso foi bem-sucedido - mas não quero definir essa propriedade do sistema para cada execução de teste. Então eu coloquei no código

@Configuration
@Import(CoreConfig.class)
@EnableAutoConfiguration
public class TestConfig {

  static {
    System.setProperty("spring.config.location", "classpath:test.properties");
  }

}

que infelizmente não foi novamente bem sucedido.

Deve haver uma solução simples sobre como substituir as application.propertiesconfigurações nos testes JUnit com as test.propertiesque eu devo ter esquecido.

FrVaBe
fonte
Se você precisar configurar apenas algumas propriedades, poderá usar a nova anotação @DynamicPropertySource. stackoverflow.com/a/60941845/8650621
Felipe Desiderati

Respostas:

293

Você pode usar @TestPropertySourcepara substituir valores em application.properties. Do seu javadoc:

as fontes de propriedades de teste podem ser usadas para substituir seletivamente as propriedades definidas nas fontes de propriedades do sistema e do aplicativo

Por exemplo:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public class ExampleApplicationTests {

}
Andy Wilkinson
fonte
2
É isso aí. Obrigado. Infelizmente, ele não funciona quando usado na classe ExampleApplication.class, então eu tenho que configurá-lo em cada classe de teste. Isso está certo?
precisa saber é
1
Ele precisa estar em algum lugar na hierarquia da classe de teste, ou seja, você pode usar uma superclasse comum para configurá-la em várias classes de teste diferentes.
21715 Andy
64
Observe também que @TestPropertySourcepode aceitar um propertiesargumento para substituir algumas propriedades em linha, como, por exemplo @TestPropertySource(properties = "myConf.myProp=valueInTest"), é útil caso você não queira um arquivo de propriedades totalmente novo.
dyng
2
Você pode especificar vários arquivos em uma matriz e também arquivos no sistema de arquivos (mas lembre-se de que eles podem não funcionar no servidor de CI):@TestPropertySource(locations={"file:C:/dev/...","classpath:test.properties"})
Adam
8
Observe que isso @SpringApplicationConfigurationjá está obsoleto e você deve usar@SpringBootTest
mrkernelpanic
74

O Spring Boot é carregado automaticamente src/test/resources/application.properties, se as seguintes anotações forem usadas

@RunWith(SpringRunner.class)
@SpringBootTest

Então, mudar o nome test.propertiespara application.propertiesutilizar a configuração automática.

Se você * apenas * precisar carregar o arquivo de propriedades (no Ambiente), também poderá usar o seguinte, conforme explicado aqui

@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class) 

[ Atualização: substituindo certas propriedades para teste ]

  1. Adicionar src/main/resources/application-test.properties.
  2. Anote a classe de teste com @ActiveProfiles("test").

Isso carrega application.propertiese, em seguida, application-test.properties propriedades no contexto do aplicativo para o caso de teste, conforme as regras definidas aqui .

Demo - https://github.com/mohnish82/so-spring-boot-testprops

Mohnish
fonte
1
Não tenho certeza se é uma boa ideia ter dois application.propertiesarquivos no caminho de classe (um src/main/resourcese outro src/test/resources). Quem garante que ambas serão tomadas e qual será a primeira?
FrVaBe
3
@FrVaBe Spring vai garantir isso! As principais propriedades do perfil são sempre carregadas. Em seguida, durante a fase de teste, as propriedades do teste são carregadas, adicionando / substituindo propriedades novas / existentes. Se não o fizer como manter dois arquivos com o mesmo nome, então você pode adicionar application-test.propertiesem src/main/resourcese especificar testcomo o perfil ativo no caso de teste.
Mohnish
7
A primavera não dá garantia. A ferramenta de construção usará os recursos de teste em favor dos principais recursos durante os testes. Porém, no caso de um application.properties de teste, o application.properties principal será ignorado. Não é isso que eu quero, porque o principal contém vários valores padrão úteis e só preciso substituir alguns deles durante o teste (e não quero duplicar o arquivo inteiro na seção de teste). Veja aqui .
FrVaBe
6
Você está correto, apenas as propriedades definidas src/test/resources/application.propertiessão carregadas durante a fase de teste e src/main/resources/application.propertiessão ignoradas.
Mohnish
11
Se você não usa perfis até agora, não precisa de um perfil de "teste" dedicado. Apenas nomeie suas propriedades de teste application-default.propertiese elas serão consideradas porque você está executando automaticamente o perfil "padrão" (se não for declarado outro).
FrVaBe
65

Você também pode usar meta-anotações para externalizar a configuração. Por exemplo:

@RunWith(SpringJUnit4ClassRunner.class)
@DefaultTestAnnotations
public class ExampleApplicationTests { 
   ...
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SpringApplicationConfiguration(classes = ExampleApplication.class)
@TestPropertySource(locations="classpath:test.properties")
public @interface DefaultTestAnnotations { }
Rob Winch
fonte
21

Outra abordagem adequada para substituir algumas propriedades em seu teste, se você estiver usando @SpringBootTest anotação:

@SpringBootTest(properties = {"propA=valueA", "propB=valueB"})
NimaAJ
fonte
1
não SpringBootTestcarregar o arquivo application.properties?
TuGordoBello
8

TLDR:

Então, o que eu fiz foi ter o padrão src/main/resources/application.propertiese também umsrc/test/resources/application-default.properties onde eu substitui algumas configurações para TODOS os meus testes.

Toda a história

Encontrei o mesmo problema e até agora não estava usando perfis. Parecia incômodo ter que fazê-lo agora e lembre-se de declarar o perfil - o que pode ser facilmente esquecido.

O truque é aproveitar que um perfil específico application-<profile>.propertiessubstitua as configurações no perfil geral. Consulte https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-profile-specific-properties .

elonderin
fonte
3

Explicação simples:

Se você é como eu e tem o mesmo application.propertiesem src/main/resourcese src/test/resources, e está se perguntando por que a application.propertiespasta na sua pasta de teste não está substituindo a dos application.propertiesseus principais recursos, continue lendo ...

Se você tem application.propertiesmenos src/main/resourcese o mesmo application.propertiesabaixo src/test/resources, que application.propertiesé detectado, depende de como você está executando seus testes . A estrutura da pasta src/main/resourcese src/test/resources, é uma convenção arquitetônica do Maven, portanto, se você executar seu teste como mvnw testou até mesmo gradlew test, o application.propertiesin src/test/resourcesserá escolhido, pois o caminho de classe de teste precederá o caminho de classe principal . Porém, se você executar seu teste como Run as JUnit Testno Elipse / STS, o application.propertiesin src/main/resourcesserá captado, pois o caminho de classe principal precede o caminho de teste .

Você pode conferir abrindo o Run > Run Configurations > JUnit > *your_run_configuration* > Click on "Show Command Line".

Você verá algo como:

XXXbin \ javaw.exe -ea -Dfile.encoding = UTF-8 -classpath XXX \ espaço de trabalho-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ main; XXX \ workspace-spring-tool-suite-4-4.5.1.RELEASE \ project_name \ bin \ test;

Você vê que \ main vem primeiro e depois \ test ? Certo, é tudo sobre o caminho de classe :-)

Felicidades

jumping_monkey
fonte
1
I just configured min as the following :

spring.h2.console.enabled=true
spring.h2.console.path=/h2-console


# changing the name of my data base for testing
spring.datasource.url= jdbc:h2:mem:mockedDB
spring.datasource.username=sa
spring.datasource.password=sa



# in testing i don`t need to know the port

#Feature that determines what happens when no accessors are found for a type
#(and there are no annotations to indicate it is meant to be serialized).
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false`enter code here`
Hilal Aissani
fonte
1

Se você estiver usando o Spring 5.2.5 e o Spring Boot 2.2.6 e quiser substituir apenas algumas propriedades, em vez de todo o arquivo. Você pode usar a nova anotação: @DynamicPropertySource

@SpringBootTest
@Testcontainers
class ExampleIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>();

    @DynamicPropertySource
    static void neo4jProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
    }
}
Felipe Desiderati
fonte
0

Caso contrário, podemos alterar o nome do configurador de propriedades padrão, definindo a propriedade spring.config.name=teste, em seguida, tendo o recurso de caminho de classe da qual src/test/test.propertiesnossa instância nativa org.springframework.boot.SpringApplicationserá configurada automaticamente a partir deste test.properties separado, ignorando as propriedades do aplicativo;

Benefício: configuração automática de testes;

Desvantagem: expor a propriedade "spring.config.name" na camada de IC

ref: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

spring.config.name = application # Nome do arquivo de configuração

D. Soloviev
fonte
5
Ignorar application.propertiesnão é uma opção para mim, pois quero substituir apenas alguns dos valores de configuração originais no teste.
FrVaBe
Eu estou procurando uma maneira de ter um único teste que não carrega o src / main / resources / application.properties e é isso. Crie um arquivo: src / test / resources / empty.properties e inclua a anotação nos testes que devem ignorar as propriedades principais. @TestPropertySource (properties = "spring.config.name = empty")
rvertigo 22/02/19
Como definir um valor de propriedade específico para cada método de teste de junção?
Nicolas
0

Você também pode criar um arquivo application.properties em src / test / resources em que suas JUnits são gravadas.

PragmaticFire
fonte
Como isso ajuda? ^^
jumping_monkey