• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Testy jednostkowe metod z logerami

VPS Starter Arubacloud
0 głosów
492 wizyt
pytanie zadane 19 sierpnia 2018 w Java przez must Bywalec (2,980 p.)
edycja 19 sierpnia 2018 przez must

Cześć. Przychodze do Was z kolejnym problemem odnośnie testów. Czytałem już masę wątków odnośnie testowania loggerów. Np ten: https://stackoverflow.com/questions/1827677/how-to-do-a-junit-assert-on-a-message-in-a-logger . Mimo to, dalej ciężko mi napisac jakikolwiek test z tego względu, że nie wiem co dokładnie ma się w nim znajdować. Z tego co wyczytałem, trzeba stworzyć swojego włansego Appendera i ciężko będzie użyć tutaj mokowania.

Metoda, którą chcę przetestować:

void getAllCustomers() throws SQLException {
    for (int i = 0; i < storage.getAllCustomers().size(); i++) {
        logger.info("Name: " + storage.getAllCustomers().get(i).getName()
                + "\nSurname: " + storage.getAllCustomers().get(i).getSurname()
                + "\nStreet: " + storage.getAllCustomers().get(i).getStreet()
                + "\nHouse number: " + storage.getAllCustomers().get(i).getHouseNumber()
                + "\nCity: " + storage.getAllCustomers().get(i).getCity()
                + "\nPesel Number: " + storage.getAllCustomers().get(i).getPeselNumber()
                + "\nRent Date: " + storage.getAllCustomers().get(i).getRentDate()
                + "\nClient number: " + storage.getAllCustomers().get(i).getClientNumber());
        logger.info("---------------------------");
    }
}

Metoda storage.getAllCustomers():

@Override
public List<Client> getAllCustomers() throws SQLException {
    List<Client> listOfClients = new ArrayList<Client>();

    String sql = "SELECT * FROM `client`";
    result = statement.executeQuery(sql);

    while (result.next()) {
        Client client = new Client();
        client.setName(result.getString("namee"));
        client.setSurname(result.getString("surname"));
        client.setStreet(result.getString("street"));
        client.setPeselNumber(result.getLong("peselNumber"));
        client.setRentDate(result.getString("rentDate"));
        client.setCity(result.getString("city"));
        client.setHouseNumber(result.getInt("houseNumber"));
        client.setClientNumber(result.getInt("clientNumber"));

        listOfClients.add(client);
    }

    return listOfClients;
}

W klasie z metodą, którą chcę przetestować używam:

 private CarRentalStorage storage;
 private Logger logger = LoggerFactory.getLogger(CarRentalOptions.class);
komentarz 19 sierpnia 2018 przez RafalS VIP (122,820 p.)
Zacząłbym od tego, że jest to napisane maksymalnie niewydajnie :D. Za każdym razem gdy chcesz cokolwiek ze storage pobierane są z bazy danych wszystkie dane, jest tworzona ich lista i wszystko po to, żeby wyciągnać pojedyńczą wartość rekordu z tej listy, która jest zapominana w kolejnej linijce i znów pobieramy wszystkie dane z bazy i tworzymy nową liste. Wszystko powtarzane 10 razy w pętli :O Żeby pobrać dane o jednym customerze 10 razy osobno pobierane są dane o wszystkich customerach i jest tworzone 10 list wszystkich customerów :O
komentarz 19 sierpnia 2018 przez must Bywalec (2,980 p.)

A nie jest dodawany obiekt do tej samej listy?

listOfClients.add(client);

Jeżeli nie, to jak to efektywnie przerobić?

komentarz 19 sierpnia 2018 przez RafalS VIP (122,820 p.)
edycja 19 sierpnia 2018 przez RafalS

Każde takie wywołanie:

storage.getAllCustomers()

tworzy nową listę wszystkich customerów. Wywołujesz tą funkcję 10 razy w jednej pętli totalnie niepotrzebnie. Stwórz jedną listę na początku i z niej korzystaj:

List<Customer> customers = storage.getAllCustomers();

korzystaj z customers a nie bombarduj bazy niepotrzebnymi zapytaniami i programu niepotrzebnym tworzeniem i niszczeniem list.

Ja bym to widział tak, że klasa Customer potrafi skonwertować się do stringa, czyli ma nadpisaną metode toString wtedy wypisanie wyglądało by tak:

    void getAllCustomers() throws SQLException {
        List<Customer> customers = storage.getAllCustomers();
        customers.forEach(logger::info);
    }

Alternatywnie są też takie opcje, jesli nie lubisz referencji do funkcji:

        customers.forEach(customer -> logger.info(customer)); //lambda
        for(Customer customer : customers){ //zwykla petla
            logger.info(customer);
        }

i nazwa jest bez sensu. GetAllCustomers, które nic nie zwraca? Jak get to get.

 

komentarz 19 sierpnia 2018 przez RafalS VIP (122,820 p.)
Druga sprawa jest taka, że metoda getAllCustomers loguje customerów. Albo metoda się źle nazywa albo to nie ma sensu.
komentarz 19 sierpnia 2018 przez RafalS VIP (122,820 p.)
Trzecia sprawa jest taka, że pierwszy raz spotykam się z testowaniem logów :D Nie wiem za co ma być odpowiedzialna klasa, która loguje bo nie widze nawet jej nazwy, ale jeśli jej funkcjonalnością jest logowanie customerów to ja czegoś nie rozumiem :P Klasa pobiera dane z bazy i dodaje je do innej "bazy" logów?
komentarz 19 sierpnia 2018 przez must Bywalec (2,980 p.)
edycja 19 sierpnia 2018 przez must
Ah.. Teraz rozumiem. Pobieramy jedną wartość, tworzymy listę, wyciągamy wartość za pomocą get(i) i tak 10 razy na jednego użytkownika.

Jeżeli chodzi o nazwę logger, to wziąłme ją stąd, ze w sumie wszyscy ją tak nazywają. Mógłbym ja równoznacznie nazwac printer.

Korzystałem z wielu linków podobnych do tego https://stackoverflow.com/questions/2727500/log4j-vs-system-out-println-logger-advantages

Podobno lepiej jest używać loggerów niż sys.out.println z wielu wymienonych w linku i na innych stronach powodów m.in są szybsze od podstawowego wypisania sys.out

Metoda ma wyciągnąc wszystkich klientów z bazy i wypisać je na ekran. Taki był zamysł i przeznaczenie tej metody.

1 odpowiedź

0 głosów
odpowiedź 20 sierpnia 2018 przez must Bywalec (2,980 p.)

Metoda, którą chce przetestować zgodnie z @RafalS radami wygląda tak:

void printPersonalDataOfClients() throws SQLException {
    List<Client> listOfClients;
    listOfClients = storage.getAllCustomers();

    for (int i = 0; i < listOfClients.size(); i++)
        logger.info(String.valueOf(listOfClients.get(i)));

}

 Moglibyście mi coś doradzić odnośnie tych testów?

1
komentarz 3 września 2018 przez mbabane Szeryf (79,280 p.)

Ja np. robiłbym to mniej więcej tak:

public class Sometests
{
    @Test
    public void unitTest() throws Exception
    {
        Optional<User> userOptional = getUserByUsernameAndPassword("ferd", "1234");
        try
        {
            User user = userOptional.orElseThrow(() -> new Exception("Błedny login lub hasło"));
            System.out.println(user);
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

    public Optional<User> getUserByUsernameAndPassword(String username, String password) throws Exception
    {
        Connection connection = DriverManager.getConnection(DB_URL, DB_USR, DB_PASS);
        PreparedStatement statement = connection.prepareStatement("SELECT id, username FROM users WHERE username=? AND password=?");

        statement.setString(1, username);
        statement.setString(2, password);

        try (ResultSet resultSet = statement.executeQuery())
        {
            if (resultSet.next())
            {
                return Optional.of(new User(resultSet.getInt(1), resultSet.getString(2)));
            }
            return Optional.empty();
        }     
    }
}

Optional ułatwia sytuację z nullami tzn. jest bardziej czytelnie niż pisanie co chwila if (object == null). I w razie gdy nie ma usera w bazie to zwracam pustego Optionala, a w metodzie gdzie używam getUserByUsernameAndPassword za pomocą orElseThrow rzucam wyjątek z informacją.

komentarz 3 września 2018 przez must Bywalec (2,980 p.)
Tylko teraz w czym to jest lepsze?
komentarz 3 września 2018 przez mbabane Szeryf (79,280 p.)
Jest wydaje mi się dużo czytelniejsze i prostsze, i nie wymaga używania co chwila if'a żeby sprawdzać czy zwrócono true czy false. Dodatkowo masz od razu obiekt User, plus o jedno mniej połączeń do bazy (o ile robisz to tak jak myślę bo w sumie do końca nie napisałeś).

Za plus można też uznać ze korzysta się z Javy 8.
komentarz 3 września 2018 przez mbabane Szeryf (79,280 p.)
Jeszcze tak napiszę. Zastosuj tę metodę, którą lepiej Ty rozumiesz - to będzie wówczas najlepszy dla Ciebie sposób, bo będziesz potrafił go omówić i uzasadnić.
komentarz 3 września 2018 przez must Bywalec (2,980 p.)

Dzięki @mbabane:)

Podobne pytania

0 głosów
0 odpowiedzi 214 wizyt
pytanie zadane 8 lipca 2017 w Java przez Sidzej Użytkownik (850 p.)
0 głosów
1 odpowiedź 157 wizyt
pytanie zadane 14 października 2019 w Java przez heartagram Obywatel (1,770 p.)
0 głosów
1 odpowiedź 140 wizyt
pytanie zadane 3 sierpnia 2018 w Java przez kamil159 Nowicjusz (180 p.)

92,454 zapytań

141,262 odpowiedzi

319,089 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...