Estou tentando escrever um teste de unidade para um bean simples que é usado no meu programa para validar formulários. O bean é anotado com@Component
e possui uma variável de classe que é inicializada usando
@Value("${this.property.value}") private String thisProperty;
Gostaria de escrever testes de unidade para os métodos de validação dentro desta classe, no entanto, se possível, gostaria de fazê-lo sem utilizar o arquivo de propriedades. Meu raciocínio por trás disso é que, se o valor que estou retirando do arquivo de propriedades for alterado, gostaria que isso não afetasse meu caso de teste. Meu caso de teste está testando o código que valida o valor, não o valor em si.
Existe uma maneira de usar o código Java dentro da minha classe de teste para inicializar uma classe Java e preencher a propriedade Spring @Value dentro dessa classe e usá-la para testar?
Eu encontrei este tutorial que parece estar próximo, mas ainda usa um arquivo de propriedades. Prefiro que tudo seja código Java.
Respostas:
Se possível, eu tentaria escrever esses testes sem o Spring Context. Se você criar essa classe em seu teste sem mola, terá controle total sobre seus campos.
Para definir o
@value
campo, você pode usar SpringsReflectionTestUtils
- ele possui um métodosetField
para definir campos particulares.@ veja JavaDoc: ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)
fonte
org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");
@Value
anotação para o parâmetro do construtor. Isso torna o código de teste muito mais simples ao escrever o código manualmente, e o Spring Boot não se importa.Desde o Spring 4.1, você pode configurar valores de propriedade apenas no código usando
org.springframework.test.context.TestPropertySource
anotação no nível da classe Testes de Unidade. Você poderia usar essa abordagem mesmo para injetar propriedades em instâncias de bean dependentesPor exemplo
Nota: É necessário ter instância de
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
no contexto do SpringEditar 24-08-2017: Se você estiver usando SpringBoot 1.4.0 e mais tarde você pode inicializar testes com
@SpringBootTest
e@SpringBootConfiguration
anotações. Mais informações aquiNo caso do SpringBoot, temos o seguinte código
fonte
Não abuse dos campos particulares que são definidos por reflexão
Usar a reflexão como isso é feito em várias respostas aqui é algo que poderíamos evitar.
Ele traz um pequeno valor aqui, enquanto apresenta várias desvantagens:
@Value String field
. Amanhã, você poderá declarar5
ou10
participar dessa classe e talvez nem esteja ciente de que diminui o design da classe. Com uma abordagem mais visível para definir esses campos (como construtor), você pensará duas vezes antes de adicionar todos esses campos e provavelmente os encapsulará em outra classe e uso@ConfigurationProperties
.Torne sua classe testável, tanto unitária quanto em integração
Para poder escrever testes de unidade simples (sem um contêiner de mola em execução) e testes de integração para sua classe de componente Spring, você deve tornar essa classe utilizável com ou sem Spring.
Executar um contêiner em um teste de unidade quando não é necessário é uma prática ruim que diminui as compilações locais: você não deseja isso.
Eu adicionei esta resposta porque nenhuma resposta aqui parece mostrar essa distinção e, portanto, eles dependem de um contêiner em execução sistematicamente.
Então, acho que você deve mover essa propriedade definida como uma parte interna da classe:
em um parâmetro construtor que será injetado pelo Spring:
Exemplo de teste de unidade
Você pode instanciar
Foo
sem Spring e injetar qualquer valorproperty
devido ao construtor:Exemplo de Teste de Integração
Você pode injetar a propriedade no contexto com o Spring Boot desta maneira simples, graças ao
properties
atributo de@SpringBootTest
:Você pode usar como alternativa,
@TestPropertySource
mas ele adiciona uma anotação adicional:Com o Spring (sem o Spring Boot), deve ser um pouco mais complicado, mas como não uso o Spring sem o Spring Boot há muito tempo, não prefiro dizer uma coisa estúpida.
Como uma observação lateral: se você tiver muitos
@Value
campos para definir, extraí-los em uma classe anotada@ConfigurationProperties
é mais relevante porque não queremos um construtor com muitos argumentos.fonte
final
, ou seja,private String final property
Se desejar, você ainda pode executar seus testes no Spring Context e definir as propriedades necessárias na classe de configuração do Spring. Se você usa JUnit, use SpringJUnit4ClassRunner e defina a classe de configuração dedicada para seus testes assim:
A classe em teste:
A classe de teste:
E a classe de configuração para este teste:
Dito isto, eu não recomendaria essa abordagem, apenas a adicionei aqui para referência. Na minha opinião, a melhor maneira é usar o corredor Mockito. Nesse caso, você não executa testes no Spring, o que é muito mais claro e mais simples.
fonte
Isso parece funcionar, embora ainda seja um pouco detalhado (eu gostaria de algo mais curto ainda):
fonte
@TestProperty
anotação.@Value
s, independentemente de a propriedade correspondente estar configurada ou não.Adicionar PropertyPlaceholderConfigurer na configuração está funcionando para mim.
E na aula de teste
fonte