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:
- detectamos problemas de reflexão apenas em tempo de execução (por exemplo: campos que não existem mais)
- Queremos um encapsulamento, mas não uma classe opaca que oculte dependências que devem ser visíveis e torne a classe mais opaca e menos testável.
- incentiva o mau design. Hoje você declara a
@Value String field
. Amanhã, você poderá declarar 5
ou 10
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:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
em um parâmetro construtor que será injetado pelo Spring:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
Exemplo de teste de unidade
Você pode instanciar Foo
sem Spring e injetar qualquer valor property
devido ao construtor:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
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
:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
Você pode usar como alternativa, @TestPropertySource
mas ele adiciona uma anotação adicional:
@SpringBootTest
@TestPropertySource("property.value=dummyValue")
public class FooTest{ ...}
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.