Non abusare dei campi privati ottenuti / impostati per riflessione
Usare la riflessione come è fatto in diverse risposte qui è qualcosa che potremmo evitare.
Porta un piccolo valore qui mentre presenta molteplici inconvenienti:
- rileviamo problemi di riflessione solo in fase di esecuzione (es: campi non esistenti più)
- Vogliamo l'incapsulamento ma non una classe opaca che nasconda le dipendenze che dovrebbero essere visibili e rendere la classe più opaca e meno verificabile.
- incoraggia il cattivo design. Oggi dichiari a
@Value String field
. Domani puoi dichiarare 5
o 10
di loro in quella classe e potresti non essere nemmeno consapevole di diminuire il design della classe. Con un approccio più visibile per impostare questi campi (come il costruttore), ci penserai due volte prima di aggiungere tutti questi campi e probabilmente li incapsulerai in un'altra classe e li utilizzerai @ConfigurationProperties
.
Rendi la tua classe testabile sia in unità che in integrazione
Per poter scrivere sia i test unitari semplici (cioè senza contenitore a molla funzionante) sia i test di integrazione per la classe dei componenti Spring, è necessario rendere questa classe utilizzabile con o senza Spring.
Eseguire un container in un unit test quando non è necessario è una cattiva pratica che rallenta le build locali: non lo vuoi.
Ho aggiunto questa risposta perché nessuna risposta qui sembra mostrare questa distinzione e quindi si basano sistematicamente su un container in esecuzione.
Quindi penso che dovresti spostare questa proprietà definita come interna alla classe:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
in un parametro del costruttore che verrà iniettato da Spring:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
Esempio di unit test
Puoi istanziare Foo
senza Spring e iniettare qualsiasi valore per property
grazie al costruttore:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
Esempio di test di integrazione
È possibile iniettare la proprietà nel contesto con Spring Boot in questo modo semplice grazie properties
all'attributo di @SpringBootTest
:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
È possibile utilizzare come alternativa @TestPropertySource
ma aggiunge un'ulteriore annotazione:
@SpringBootTest
@TestPropertySource("property.value=dummyValue")
public class FooTest{ ...}
Con Spring (senza Spring Boot), dovrebbe essere un po 'più complicato, ma dato che non ho usato Spring senza Spring Boot da molto tempo non preferisco dire una cosa stupida.
Come nota a margine: se hai molti @Value
campi da impostare, estrarli in una classe annotata @ConfigurationProperties
è più rilevante perché non vogliamo un costruttore con troppi argomenti.