Spring Framework testowanie DAO z użyciem adnotacji

Ostatnimi czasy siedzę trochę w Spring Framework, frameworku dla Javy. Doszedłem do etapu testów i stwierdziłem, że godnym opisania będzie sposób testowania metod opartych o transakcje, gdyż ciekawym jest fakt iż wszystko co odbywa się w danych testach (dodawanie danych, edycja itd.) jest następnie cofane do wersji pierwotnej (wywoływany jest rollback na transakcji) i dzieje się to automatycznie.

Poniżej znajduje się przykładowa klasa wraz z metodami testującymi. Wszystko oparte jest na adnotacjach, więc nie ma problemu:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:test-config.xml"
public class UserAccountDaoImplTest {

    @Resource
    UserAccountDaoImpl userAccountDao;

    @Test
    @Transactional
    public void testSaveUser() {
        UserAccount transientInstance = new UserAccount();
        transientInstance.setEmail("email@mail.con");
        transientInstance.setEnabled(true);
        userAccountDao.saveUser(transientInstance);
        UserAccount userFromDb = userAccountDao.getByEmail("email@mail.con);
        assertNotNull("User should be not null", userFromDb);
        assertTrue("User should be enabled", userFromDb.isEnabled());
        assertTrue("User should no be locked", userFromDb.isAccountNonLocked());
    }

    @Test(expected = ConstraintViolationException.class)
    @Transactional
    public void testSaveUserDuplicateEmail() {
        System.out.println("saveUserDuplicateEmail");
        UserAccount transientInstance = new UserAccount();
        transientInstance.setEmail("michal@somedomain.pl");
        userAccountDao.saveUser(transientInstance);
    }

    @Test
    @NotTransactional
    public void testGetUserById() {
        long id = 1L;
        UserAccount result = userAccountDao.getUserById(id);
        assertNotNull("User with id " + id + " should be found", result);
        assertEquals(new Long(id), result.getId())        id = 667L;
        result = userAccountDao.getUserById(id);
        assertNull("User with id " + id + " should not be found", result);
    }

    @Test(expected = UsernameNotFoundException.class)
    @NotTransactional
    public void testGetByEmailNoUser() {
        System.out.println("getByEmailNoUser");
        String email = "someone@gnail.con";
        userAccountDao.getByEmail(email);
    }
}

Początkowo inicjujemy kontekst springa (definiujemy która klasa się tym zajmie i dodajemy plik konfiguracyjny).

1
2
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = classpath:test-config.xml)

Następnie musimy wstrzyknąć do testu instancję którą testujemy, wykorzystujemy do tego adnotację @Resource:

5
6
@Resource
UserAccountDaoImpl userAccountDao;

Nie będę tutaj opisywał adnotacji czystego JUnita, zwrócę jedynie uwagę na adnotacje potrzebne przy testowaniu danych opartych o DB. Tak więc mamy:

@Transactional – określa nam, że dana metoda korzysta z transakcji i ma być wykonany rollback @NotTransactional – odwrotnie do tego wyżej

Dodatkowo, co nie zostało pokazane na powyższym przykładzie, możemy skorzystać z adnotacji @Rollback(false) jeżeli nie chcemy, aby wykonywany był rollback po wykonaniu testu.

Mam nadzieję, że powyższy (działający u mnie) przykład komuś się przyda. Ja chwilę spędziłem, zanim doprowadziłem go do porządku, choć okazało się to niezwykle proste (wynik końcowy),