Testowanie JdbcTemplate, JUnit4, Mockito

0

Witam,

Chcialbym przetestować poniższą metodę za pomocą JUnit4 oraz Mockito. Czy mógłby ktoś bardziej doświadczony w temacie testowania naprowadzić mnie w jaki sposób można by to najlepiej rozwiązać? W przypadku zwracania jednej wartości jakiegoś typu to nie problem, jednak zastanawiam się w jaki sposób poradzić sobie z RowMapperem

public List<Assortment> getAssortmentList(String numer) throws IntegrationServiceException{
        logger.debug("Pobieranie informacji ...");

        String sql;

        if(numer == null) {
            sql = "SELECT ID," //
                    + " NAZWA," //
                    + " NUMER1," //
                    + " NUMER2" //
                    + " FROM TABELA1";
        } else {
            sql =  "SELECT ID," //
                    + " NAZWA,"
                    + " NUMER1," //
                    + " NUMER2" //
                    + " FROM TABELA1" //
                    + " WHERE NUMER1 = " + numer;
        }
        try {
            return getJdbcTemplate().query(sql, new RowMapper<Assortment>() {
                @Override
                public Assortment mapRow(ResultSet resultSet, int i) throws SQLException {
                    Assortment assortment = new Assortment();
                    assortment.setAssortmentId(resultSet.getInt("ID"));
                    assortment.setAssortmentName(resultSet.getString("NAZWA"));
                    assortment.setAssortmentTableNumber(resultSet.getInt("NUMER1"));
                    assortment.setAssortmentRowNumber(resultSet.getInt("NUMER2"));
                    return assortment;
                }
            });
        } catch(Exception e) {
            logger.error("Błąd podczas pobierania listy pozycji ...");
            throw new IntegrationServiceException("Błąd podczas pobierania listy pozycji ...", e);
        }
    }
2

Ja bym zaczął od dekompozycji bo widzę tutaj metodę która powinna być podzielona na przynajmniej 3-4 mniejsze.
Poza tym zastanów sie CO konkretnie chcesz tu testować.

edit: w ramach wyjaśnienia -> jeśli to sobie zdekomponujesz to zobaczysz że niewiele tu jest do testowania i w zasadzie jest to trywialne. Ten pierwszy if-else to powinny być 3 metody (jeśli nie chcesz sie bawić w rozbijanie tego na polimorficzne klasy :P) i na dobrą sprawę nie ma co w nich testować chyba że chcesz robić asercje czy return "ala ma kota" zwraca stringa ala ma kota. Jedyne co można przetestować to czy faktycznie dodaje nam where jeśli zdeklarujesz numer.
W efekcie masz test na zapytanie, a w metodzie getAssortmentList masz już tylko wywołanie przetestowanej metody.

Kolejna dekompozycja to to twoje mapowanie ResultSeta na Assortment. Znów leci to do osobnej metody. Możesz sobie mockować ResultSet i sprawdzić czy mapping przypisuje wartości z ResultSeta do poprawnych pól.

I co się okazuje? Że jedyne co nam zostaje to odpalenie query, które jest w zewnętrznej bibliotece. Możesz sobie ewentualnie dopisać test który sprawdzi czy obsługa błędów jest poprawna, tzn czy jeśli mockowany jdbcTemplate rzuci wyjątkiem to test rzuci tym twoim IntegrationServiceException.

0

Dzięki za szybką odpowiedź. Co do metody, akurat wymagała tego sytuacja aby była wykonana w taki sposób dlatego tak zrobiłem (chociaż fakt niektóre rzeczy aż się proszą aby je rozdzielić :) ). Jeżeli chodzi o testowanie, myśle że większość problemów wynikało z mojej niewiedzy ponieważ nigdy wcześniej tego nie robiłem, teraz już mniej więcej rozumiem. Faktyczni nie ma zbyt wiele do testowania ale miałem wymóg aby prawie cały kod był pokryty testami (nawet trywialnymi). Już mi się udało większośc rozwiązać ale mam jeszcze takie pytanie. Czy jest możliwosc zamockowania klasy parametryzowanej? Chodzi mi np o coś takiego (na przykładzie RowMappera)

Chciałbym aby mój JdbcTemplate zamiast odwoływać się do rzeczywistej bazy danych, zwrócił mi jakiś oczekiwany (wcześniej zdefiniowany) rezultat. I dalej już zrobić sobie jakieś asercje. Już pomijając fakt, że może i to jest bez sensu, chciałbym wiedzieć jak takie coś rozwiązać. Na przykłądzie metody:

queryForObject(String sql, RowMapper<T> rowMapper)

W tym przypadku dla argumentu "sql" nie ma problemu robie to za pomocą Mockito.anyString() ale co z RowMapperem? jak mogę to rozwiązać

Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), CoTutaj? )).ThenReturn(ExpectedResult);
0

Co do metody, akurat wymagała tego sytuacja aby była wykonana w taki sposób dlatego tak zrobiłem

Sytuacja wymagała napisania słabego kodu? Śmiem wątpić. Stał ktoś nad tobą z pistoletem i mówił pisz słaby kod! i ani mi się waż pisać tego elegancko!? ;)
2. Ja jestem z tych co wolą EasyMocka ;) Niemniej mockito musi mieć jakieś anyObject, nie powiesz mi że nie ;]

1 użytkowników online, w tym zalogowanych: 0, gości: 1