Nie nadużywaj prywatnych pól, które zostaną ustawione / ustawione przez odbicie
Używanie refleksji tak, jak ma to miejsce w kilku odpowiedziach, jest czymś, czego możemy uniknąć.
Przynosi tutaj małą wartość, a jednocześnie ma wiele wad:
- wykrywamy problemy z odbiciem tylko w czasie wykonywania (np. pola już nie istnieją)
- Chcemy enkapsulacji, ale nie nieprzezroczystej klasy, która ukrywa zależności, które powinny być widoczne, a klasa bardziej nieprzejrzysta i mniej testowalna.
- zachęca do złego projektu. Dziś deklarujesz
@Value String field
. Jutro możesz zadeklarować 5
lub jedną 10
z nich w tej klasie i możesz nawet nie być świadomy, że zmniejszysz projekt klasy. Przy bardziej widocznym podejściu do ustawiania tych pól (takich jak konstruktor), pomyślisz dwa razy przed dodaniem wszystkich tych pól i prawdopodobnie zamkniesz je w innej klasie i użyjesz @ConfigurationProperties
.
Spraw, by Twoja klasa była testowalna zarówno jako jednolita, jak i integracyjna
Aby móc pisać zarówno zwykłe testy jednostkowe (bez działającego kontenera sprężynowego), jak i testy integracyjne dla klasy komponentów Spring, musisz uczynić tę klasę użyteczną ze sprężyną lub bez niej.
Uruchamianie kontenera w teście jednostkowym, gdy nie jest to wymagane, jest złą praktyką, która spowalnia lokalne kompilacje: nie chcesz tego.
Dodałem tę odpowiedź, ponieważ żadna odpowiedź tutaj nie wydaje się wykazywać tego rozróżnienia, więc polegają one systematycznie na działającym kontenerze.
Myślę więc, że powinieneś przenieść tę właściwość zdefiniowaną jako wewnętrzna klasy:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
do parametru konstruktora, który zostanie wstrzyknięty przez Spring:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
Przykład testu jednostkowego
Możesz utworzyć instancję Foo
bez Springa i wstrzyknąć dowolną wartość property
dzięki Konstruktorowi:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
Przykład testu integracji
Możesz wstrzyknąć właściwość w kontekście za pomocą Spring Boot w ten prosty sposób dzięki properties
atrybutowi @SpringBootTest
:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
Możesz użyć jako alternatywy, @TestPropertySource
ale dodaje to dodatkową adnotację:
@SpringBootTest
@TestPropertySource("property.value=dummyValue")
public class FooTest{ ...}
W przypadku Spring (bez Spring Boot) powinno to być trochę bardziej skomplikowane, ale ponieważ od dłuższego czasu nie używałem Spring bez Spring Boot, nie wolę mówić głupio.
Na marginesie: jeśli masz wiele @Value
pól do ustawienia, wyodrębnienie ich do klasy opatrzonej adnotacjami @ConfigurationProperties
jest bardziej odpowiednie, ponieważ nie chcemy konstruktora z zbyt dużą liczbą argumentów.