Testy integracyjne walidatorów Hibernate
Gdy pierwszy raz pisałem o walidatorze Hibernate dla NIP, utworzyłem jedynie testy jednostkowe, pozwalające sprawdzić poprawność działania samego algorytmu. Dla przypomnienia, poniżej przedstawiam użytą wówczas metodę testową:
@Test(dataProvider="nipValidator.isValid")
public void testIsValid(
NIP annotation, Object value, boolean valid) {
validator.initialize(annotation);
assert validator.isValid(value) == valid :
"Validation result is wrong.";
}
Nic jednak nie wskazuje na to, aby testowany walidator miał działać prawidłowo przy próbie zapisania danych do bazy. Nie jestem nawet pewien, czy użyty przeze mnie interfejs (org.hibernate.validator.Validator) jest tym właściwym.
Postanowiłem skorzystać z najprostszego sposobu na wywołanie walidatora z poziomu biblioteki Hibernate. Klasą, używaną do walidacji danych przy próbie zapisu encji przez Java Persistence API jest org.hibernate.validator.event.JPAValidateListener. Aby skorzystać z tego obserwatora, nie potrzeba żadnej dodatkowej konfiguracji – wystarczy utworzenie instancji:
private final JPAValidateListener jpaValidateListener =
new JPAValidateListener();
Do wykonania testu potrzebne jest jedynie wywołanie metody onChange dla odpowiedniego obiektu, będącego w założeniu encją. W testach wykorzystałem do tego celu specjalnie przygotowane klasy z pakietu pl.info.czerwinski.validators.mock, które można znaleźć w repozytorium projektu.
Poniżej przedstawiłem metodę testową wraz z danymi wejściowymi dla kilku prawidłowych NIP:
@Test(dataProvider="validNIP")
public void testValid(Object entity) {
jpaValidateListener.onChange(entity);
}
@DataProvider(name="validNIP")
public Object[][] getValidNIPEntities() {
return new Object[][] {
{new NIPMock(null)},
{new NIPMock("123-456-32-18")},
{new NIPMock("123-45-63-218")},
{new NIPMock("1234563218")},
{new NIPMock("PL1234563218")},
{new NIPMock("PL 1234563218")},
// …
};
}
Coś tutaj nie pasuje. Każdy test powinien składać się z trzech etapów: inicjalizacja (tę zapewnia dataProvider), wykonanie operacji (linia 3) i sprawdzenie rezultatów. Ostatni krok nie występuje w powyższym kodzie, więc jak można mówić o testowaniu?
Tak się składa, że w przypadku braku poprawnej walidacji, metoda onChange zgłasza wyjątek org.hibernate.validator.InvalidStateException. Jego brak oznacza zatem prawidłową wartość NIP.
Co ciekawe, metoda sprawdzająca niewłaściwe wartości NIP wygląda identycznie… za wyjątkiem atrybutu expectedExceptions (linia 2):
@Test(dataProvider="invalidNIP",
expectedExceptions=InvalidStateException.class)
public void testInvalid(Object entity) {
jpaValidateListener.onChange(entity);
}
@DataProvider(name="invalidNIP")
public Object[][] getInvalidNIPEntities() {
return new Object[][] {
{new NIPMock("123456321a")},
{new NIPMock("1234563210")},
{new NIPMock("1235563210")},
// …
};
}
W tym wypadku, aby test zakończył się sukcesem, wymagane jest wystąpienie wspomnianego wyjątku InvalidStateException, co oznacza błąd walidacji.
Oczywiście wciąż przydałyby się pełne testy akceptacyjne walidatorów, zawierające podstawową konfigurację połączenia z bazą danych. Jednak powyższy przykład daje ogólne pojęcie o użyciu walidatora przez Hibernate, będąc dużo prostszym i szybszym w działaniu.



