Próbuję napisać test jednostkowy dla prostej fasoli, która jest używana w moim programie do sprawdzania poprawności formularzy. Fasola jest opatrzona adnotacjami @Component
i ma zmienną klasy, która jest inicjowana za pomocą
@Value("${this.property.value}") private String thisProperty;
Chciałbym napisać testy jednostkowe dla metod sprawdzania poprawności w tej klasie, jednak jeśli to możliwe, chciałbym to zrobić bez korzystania z pliku właściwości. Moje uzasadnienie jest takie, że jeśli wartość, którą pobieram z pliku właściwości, zmienia się, chciałbym, aby nie miało to wpływu na mój przypadek testowy. Mój przypadek testowy testuje kod, który sprawdza wartość, a nie samą wartość.
Czy istnieje sposób użycia kodu Java w mojej klasie testowej do zainicjowania klasy Java i wypełnienia właściwości Spring @Value w tej klasie, a następnie użycia jej do przetestowania?
Znalazłem ten poradnik, który wydaje się być blisko, ale nadal używa pliku właściwości. Wolałbym, żeby to wszystko był kod Java.
Odpowiedzi:
Jeśli to możliwe, spróbuję napisać te testy bez kontekstu wiosny. Jeśli utworzysz tę klasę w teście bez wiosny, masz pełną kontrolę nad jej polami.
Aby ustawić
@value
pole, możesz użyć SprężynReflectionTestUtils
- ma metodęsetField
ustawiania pól prywatnych.@ patrz JavaDoc: ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)
źródło
org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");
@Value
adnotację do parametru konstruktora. To znacznie upraszcza kod testowy podczas ręcznego pisania kodu, a Spring Boot nie dba o to.Od wiosny 4.1 można ustawić wartości właściwości tylko w kodzie, używając
org.springframework.test.context.TestPropertySource
adnotacji na poziomie klasy testów jednostkowych. Można użyć tego podejścia nawet do wstrzykiwania właściwości do zależnych instancji komponentu beanNa przykład
Uwaga: Konieczne jest posiadanie instancji
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
w kontekście wiosennymEdytuj 24-08-2017: Jeśli używasz SpringBoot 1.4.0 i nowszych, możesz zainicjować testy za pomocą
@SpringBootTest
i@SpringBootConfiguration
adnotacji. Więcej informacji tutajW przypadku SpringBoot mamy następujący kod
źródło
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:
@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:
do parametru konstruktora, który zostanie wstrzyknięty przez Spring:
Przykład testu jednostkowego
Możesz utworzyć instancję
Foo
bez Springa i wstrzyknąć dowolną wartośćproperty
dzięki Konstruktorowi: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
:Możesz użyć jako alternatywy,
@TestPropertySource
ale dodaje to dodatkową adnotację: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.źródło
final
, tj.private String final property
Jeśli chcesz, możesz nadal uruchamiać testy w ramach Spring Context i ustawiać wymagane właściwości w klasie Spring. Jeśli używasz JUnit, użyj SpringJUnit4ClassRunner i zdefiniuj dedykowaną klasę konfiguracji dla swoich testów w ten sposób:
Testowana klasa:
Klasa testowa:
I klasa konfiguracji dla tego testu:
Powiedziawszy to, nie zalecałbym tego podejścia, po prostu dodałem go tutaj w celach informacyjnych. Moim zdaniem znacznie lepszym sposobem jest użycie biegacza Mockito. W takim przypadku nie uruchamiasz testów wewnątrz Springa, co jest znacznie bardziej przejrzyste i prostsze.
źródło
Wydaje się, że to działa, choć wciąż jest trochę gadatliwe (chciałbym jeszcze coś krótszego):
źródło
@TestProperty
adnotacji.@Value
, niezależnie od tego, czy odpowiednia właściwość jest ustawiona, czy nie.Dodanie PropertyPlaceholderConfigurer do konfiguracji działa dla mnie.
I w klasie testowej
źródło