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

Dlaczego po dodaniu adnotacji @Mock wywala mi java.lang.NullPointerException

Object Storage Arubacloud
0 głosów
1,897 wizyt
pytanie zadane 12 sierpnia 2018 w Java przez must Bywalec (2,980 p.)

Cześć. Możecie mi powiedzieć, dlaczego po dodaniu adnotacji @Mock wywala mi NPE?

Tak działa normalnie. Test przechodzi:

@Test
    void createNewCustomer() throws SQLException {
        CarRentalStorage carRentalStorageMock = mock(CarRentalStorage.class);

        CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);
        Client client = new Client();

        carRentalOptions.createNewCustomer(client);

        List<Client> listOfClients = new ArrayList<Client>();
        listOfClients.add(client);

        verify(carRentalStorageMock).addClient(client);

        when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);

        assertEquals(1, listOfClients.size());
    }

Jeżeli zrobie coś takiego:

@RunWith(MockitoJUnitRunner.class)
class CarRentalOptionsTest {

    @Mock
    CarRentalStorage carRentalStorageMock;
    @Test
    void createNewCustomer() throws SQLException {
        //CarRentalStorage carRentalStorageMock = mock(CarRentalStorage.class);

        CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);
        Client client = new Client();

        carRentalOptions.createNewCustomer(client);

        List<Client> listOfClients = new ArrayList<Client>();
        listOfClients.add(client);

        verify(carRentalStorageMock).addClient(client);

        when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);

        assertEquals(1, listOfClients.size());
    }
}

Wywala mi NPE.

 

komentarz 12 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
W ktorym miejscu?
komentarz 12 sierpnia 2018 przez must Bywalec (2,980 p.)
java.lang.NullPointerException
	at CarRental.CarRentalOptions.createNewCustomer(CarRentalOptions.java:17)
	at CarRental.CarRentalOptionsTest.createNewCustomer(CarRentalOptionsTest.java:30)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:515)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
	at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:134)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1378)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1378)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:49)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:47)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:184)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:152)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:166)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:145)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:92)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

 

komentarz 12 sierpnia 2018 przez must Bywalec (2,980 p.)

Na pewno inaczej linijki będą się nie zgadzać, bo nie kopiowałem całej klasy. 

Dlatego tutaj cała klasa:

package CarRental;

import CarRental.Model.Client;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
class CarRentalOptionsTest {

    @Mock
    CarRentalStorage carRentalStorageMock;
    @Test
    void createNewCustomer() throws SQLException {
        //CarRentalStorage carRentalStorageMock = mock(CarRentalStorage.class);

        CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);
        Client client = new Client();

        carRentalOptions.createNewCustomer(client);

        List<Client> listOfClients = new ArrayList<Client>();
        listOfClients.add(client);

        verify(carRentalStorageMock).addClient(client);

        when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);

        assertEquals(1, listOfClients.size());
    }
}

 

komentarz 12 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Czemu when () masz po wywołaniu metody?
komentarz 12 sierpnia 2018 przez must Bywalec (2,980 p.)
W sensie? Jest to mój pierwszy test dlatego mogę nie ogarniać tematu.
komentarz 12 sierpnia 2018 przez Wiciorny Ekspert (270,170 p.)

@Mock - nie tworzy inicjalizacji, generalnie tylko informuje że ten element będzie Mockowany.

jest to różnica pomiędzy Inicjalizacja @InjectMock - np kiedy korzystamy z automatycznego wstrzykiwania -> w teestach Springowych

z drugiej strony, też nie zauważyłem gdzie inicjalizacja/tworzenie mocka zachodzi

 new CarRentalOptions(carRentalStorageMock);

posyłasz pusty obiekt do CarRentalOptions tak naprawdę 

komentarz 12 sierpnia 2018 przez Mateusz Dąbrowski Użytkownik (700 p.)
when() powinien być wywołany przed

carRentalOptions.createNewCustomer(client); bo pewnie w tej metodzie masz wywołanie carRentalStorageMock.getAllCustomers()

Mokuje się wywołanie funkcji zanim ona zostanie użyta.

Poza tym twoja asercja assertEquals(1, listOfClients.size()); sprawdza czy lista którą ustawiłeś w teście ma rozmiar 1 - zawsze ma rozmiar jeden i asercja zawsze będzie prawdziwa, bo llista po inicjalizacji nigdy nie jest zmieniana (w takiej formie jest niepotrzebna)

Co do NPE to trudno coś powiedzieć bez kodu klasy, którą testujesz
komentarz 13 sierpnia 2018 przez must Bywalec (2,980 p.)
edycja 13 sierpnia 2018 przez must

ale skoro when cały czas pozostaje w miejscu nie zmieniam kolejności, a 

CarRentalStorage CR = mock(CarRentalStorage.class) /= @Mock CarCarRentalStorage CR

A z filmku wynika, ze jest to równe: https://www.youtube.com/watch?v=2dpUw0WQqAs&feature=youtu.be&t=2m15s

To jak raz działa a raz nie, jaka jest ta główna róznica pomiędzy tym. 

Tam ziomek na filmiku bez dodania @InjectMock odpala test i mu wszystko działa.

 

Poza tym twoja asercja assertEquals(1, listOfClients.size()); sprawdza czy lista którą ustawiłeś w teście ma rozmiar 1 - zawsze ma rozmiar jeden i asercja zawsze będzie prawdziwa, bo llista po inicjalizacji nigdy nie jest zmieniana (w takiej formie jest niepotrzebna)

W takim razie mój test jest błędny? Na samym początku lista ma 0 size, czyż nie? Później dodaje klienta, wiec rozmiar się zwiększa +1.

 

when() powinien być wywołany przed 

carRentalOptions.createNewCustomer(client); bo pewnie w tej metodzie masz wywołanie carRentalStorageMock.getAllCustomers()

False. 

void createNewCustomer(Client client) throws SQLException {
    storage.addClient(client);
}

Tam nie ma żadnego związku z getAllCustomers.

Nie rozumiem dlaczego to ma być wywołane przed carRentalOptions.createNewCustomer(client)

 

komentarz 13 sierpnia 2018 przez Wiciorny Ekspert (270,170 p.)

na marginesie 

the object in when() must be a mock created by Mockito.mock(), it does not work for manually created real objects - not sure if that's your issue, since I'm not really getting where your problem is.

więc tutaj @Mockiem  musisz przez @InjectMcok wstawić Clienta.  

3 odpowiedzi

+1 głos
odpowiedź 14 sierpnia 2018 przez Mateusz Dąbrowski Użytkownik (700 p.)
wybrane 15 sierpnia 2018 przez must
 
Najlepsza

To co próbujesz zrobić to testowanie metody, która zwraca void co jest trochę trudniejsze od testowania metody, która coś zwraca. Jedyny sposób żeby przetestować taką metodę to veryfikacja mocka (co właściwie robisz, ale nie do końca poprawnie). 

Tak powinien wyglądać test:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class CarRentalOptionsTest {

    @Mock
    private CarRentalStorage storage;

    private CarRentalOptions carRentalOptions;

    @Before
    public void setUp() {
        carRentalOptions = new CarRentalOptions(storage);
    }

    @Test
    public void shouldAddClient() throws SQLException {
        //given
        Client client = new Client();
        doNothing().when(storage).addClient(any(Client.class));
        //when
        carRentalOptions.createNewCustomer(client);
        //then
        verify(storage).addClient(eq(client));
    }
}

A teraz opis:
testujesz metodę 

carRentalOptions.createNewCustomer(client);

więc musisz zamokować zależności, które są wywoływane w tej metodzie, czyli storage.addClient(client):

void createNewCustomer(Client client) throws SQLException {
        storage.addClient(client);
}

storage.addClient(client) (prawdopodobnie) zwraca void czyli nie możesz zamokować jej przez when

tylko tak:

doNothing().when(storage).addClient(any(Client.class));

I teraz veryfikacja mocka:

verify(storage).addClient(eq(client));

Co robi weryfikacja mocka: sprawdza czy w twojej testowanej metodzie createNewCustomer metoda, która jest wywoływana storage.addClient(client) otrzymuje jako parametr clent, który ustawiasz w teście.

W verify sprawdza się to używając matcher'a eq(client).

Pozostałe rzeczy które robisz:

List<Client> listOfClients = new ArrayList<Client>();
listOfClients.add(client);
when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);
assertEquals(1, listOfClients.size());

są niepotrzebne, getAllCustomers() w metodzie testowej nie jest wywoływane, więc niepotrzebnie to mokujesz. A lista, o której już pisałem, jest zwracana tylko w mocku, którego nie używasz .thenReturn(listOfClients), więc cały ten fragment jest niepotrzebny.

Rozumiem, że chcesz sprawdzić czy klient się zapisał, ale w ten sposób możesz to próbować robić w teście integracyjnym a nie jednostkowym, a to już inna historia...

komentarz 14 sierpnia 2018 przez Wiciorny Ekspert (270,170 p.)
doNothing().when(storage).addClient(any(Client.class));

tak się nie testuje metod tzn... jeśli nie można metody void przetestować na bazie EXCEPTION to znaczy że defakto metoda jest już na starcie sama w sobie błędna. 

z punktu widzenia SOLID/ CZY OPP  

komentarz 14 sierpnia 2018 przez Mateusz Dąbrowski Użytkownik (700 p.)
To akurat jest mokowanie metody, która zwraca void. Jesli musisz z jakiś względów zamokować metodę void'ową to robisz to właśnie w taki sposób. Chcesz czy nie metody voidowe istnieją, więc musisz je jakoś mokować. Metoda void'owa nie musi zwracać exceptio, może po prostu sobie być.

Ja opisałem tylko jak trzeba przetestować dany kod, nie zgłębiając się w jego design...

I nie rozumiem co ma do tego SOLID i OPP ?
komentarz 15 sierpnia 2018 przez must Bywalec (2,980 p.)

Cześć. Dzięki za odpowiedź i za test, dziś w wolnym czasie przeglądne dokładnie ten test.

Mam pytanie, co o nim myślisz:

@RunWith(MockitoJUnitRunner.class)
public class CarRentalOptionsTest {

    @Mock
    private CarRentalStorage carRentalStorageMock;
    private Client client;

    @Before
    public void setup() throws SQLException {
        CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);
        client = new Client();

        carRentalOptions.createNewCustomer(client);

        List<Client> listOfClients = new ArrayList<Client>();
        listOfClients.add(client);
    }

    @Test
    public void createNewCustomer() throws SQLException {

        verify(carRentalStorageMock).addClient(client);

    }
}
komentarz 15 sierpnia 2018 przez Mateusz Dąbrowski Użytkownik (700 p.)

Przyjrzyj się mojemu testowi, to taki szablom 99% testów wygląda podobnie do tego testu. 

w setup masz zwykle to co jest wspólne dla wszystkich testów danej klasie (możesz w klasie umieścić kilka testów). A same testy zawsze będą wyglądać podobnie. 

cześć //given ustawiasz wszystko co potrzebujesz do przetestowania metody: obiekty (client), mocki

część //when tu umieszczasz to co testujesz zwykle jest to jedna metoda z testowanej klasy (stąd też nazwa testy jednostkowe - testujesz jakąś jednostkę np. metodę)

część //then tu umieszczasz wszystkie asercje i veryfikacje moków

i tylko tyle, to jest bardzo hermetyczna struktura.

Przeczytaj jeszcze raz co napisałem wyżej i przeanalizuj dokładnie. Powinno ci się  rozjaśnić. Powodzenia ;)

komentarz 15 sierpnia 2018 przez must Bywalec (2,980 p.)

Zrobiłem bardoz podobnie tylko bez tej linijki.

doNothing().when(storage).addClient(any(Client.class));

Opłaca się ją dawać skoro i tak nic nie robi?

komentarz 15 sierpnia 2018 przez Mateusz Dąbrowski Użytkownik (700 p.)
Możesz ją oczywiście pominąć, tak jak napisałeś, nic ona nie robi. Ale czasem możesz chcieć napisać to dla czytelności testu. Poza tym możesz jeszcze używać doAnswer() i doThrow() do mockowania zachowań method void.
komentarz 15 sierpnia 2018 przez must Bywalec (2,980 p.)
dzieki wielkie!
0 głosów
odpowiedź 12 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
przywrócone 12 sierpnia 2018 przez Aisekai
O ile dobrze mi wiadomo, tworząc mocka tak na prawde tworzysz "zaślepkę" czegos. Wiec w przypadku, gdy jest wywoływana metoda z obiektu będącego Mockiem, jest ona "defaultowo ignorowana". NPE prawdopodobnie pojawia Ci sie, gdyz chcesz przypisać coś do zmiennej, używając jakiejś metody z Mocka, a następnie próbujesz coś wykonać jakąś metodę czy coś, na tej zmiennej.

Edit:

Zakładam, ze ten w ktoryms miejscu CarRentalStorage zwraca jakas listę Clientow, którą w tym miejscu gdzieś używasz: carRentalOptions.createNewCustomer(client).

Jeżeli ta lista, podczas używania nie została utworzona, to wywołanie na niej jakiejkolwiek metody zwroci NPE.

Problem wedlug mnie może być w tym, że przed wywołaniem metody na @Mock powinieneś dac when() i powiedzieć co w chwili wywołania metody zwrócić. Używałeś debbugera?
komentarz 13 sierpnia 2018 przez must Bywalec (2,980 p.)
Źle to może napisałem.

Metoda która testuje zawiera w sobie inną metodę, która jest odpowiedzialna za dodawanie do bazy danych klientów.
komentarz 13 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)

Dobra, inaczej postaram się wytłumaczyć czemu When ma być przed wyowłaniem metody Mocka:

Jest sobie Heniek. Heniek poszedł na rozmowę kwalifikacyjną do jakiejś firmy gdzie będzie zajmował się sprawdzaniem czy końcowa cena na fakturze została odpowiednio wyliczona. Dla uproszczenia, załóżmy że cena na fakturze będzie sumą poszczególnych towarów. Heniek wyciąga odpowiednią fakturę z szafki - bazy danych. Heniek dostał kartkę z zadaniami które miałby robić, jakby został przyjęty, dostał za zadanie sprawdzenie czy faktura z dnia 13-12-13  jest dobrze podliczona. Więc idzie do drugiej osoby (RepozytoriumFaktur), żeby mu wydała tą fakturę (tak było napisane na kartce) - niestety takiej faktury nie ma. Więc zgłasza osobie, że faktury nie ma (NPE). Więc osoba, odpowiedzialna za rozmowę kwalifikacyjna, poszła do tej drugiej osoby i powiedziała jej: "kiedy Heniek przyjdzie i poprosi o fakturę z 13-12-13 to daj mu tą i powiedz, że o tą chodziło". Potem Heniek sprawdził i okazało się, że jest dobrze wypełniona. 

A więc tak: w twoim przypadku Heniek to jest test (metoda testująca), osoba wydająca fakturę (RepozytoriumFaktur) powiedzmy z szafki (Bazy Danych) to mockowany obiekt, a liczenie ceny końcowej faktury to jest testowana metoda. Jeżeli dodasz adnotację nad RepozytoriumFaktur @Mock, to tak jakbyś postawił człowieka spod sklepu przed szafką z Fakturami i powiedział mu, że ktolowiek przyjdzie i zacznie coś mówić ma powiedzieć "Nie ma". Jeżeli chciałbyś, by ta osoba wydała jakąś fakturę Heńkowi, musiałbyś przed przyjściem Heńka do tej osoby powiedzieć, że jak Heniek przyjdzie to żeby mu wydała Fakturę. Do tego służy when i to by było coś takiego:

when(heniek.poprosiOFakture()).thenReturn(przykładowaFaktura)
heniek.sprawdźFakturęZDnia(13-12-13);

 

komentarz 13 sierpnia 2018 przez must Bywalec (2,980 p.)

Troche zamotana ta historia :P 

@Mock, to tak jakbyś postawił człowieka spod sklepu przed szafką z Fakturami i powiedział mu, że ktolowiek przyjdzie i zacznie coś mówić ma powiedzieć "Nie ma". Jeżeli chciałbyś, by ta osoba wydała jakąś fakturę Heńkowi, musiałbyś przed przyjściem Heńka do tej osoby powiedzieć, że jak Heniek przyjdzie to żeby mu wydała Fakturę.

To jeszcze raz. 

1) Piszesz, że sam @Mock .... bez inicjalizacji nic nie zrobi.

Dlaczego tylko po dodaniu @Mock ... ziomkowi wszystko działa https://www.youtube.com/watch?v=2dpUw0WQqAs&feature=youtu.be&t=2m15s .

2) Piszesz, że kogos trzeba postawić, masz na myśli:

@Before
public void setUp(){
    initMocks(this);
}

Z tym też mi nie działa i dalej wywala NPE.

3) Czyli metoda, którą chce przetestować zawsze ma być po when()?

 

 

 

komentarz 13 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)

Nie mam czasu na oglądanie całego tego filmiku ale:

1)Nie mówię, że @Mock bez inicjalizacji nic nie robi. Wręcz przeciwnie, robi - jeżeli mockujesz jakąś klasę to tak naprawdę tworząc zaślepkę defaultowo "ignorujesz wszystkie metody tej klasy". Załóżmy sytuację (prawdopodobnie kod się nawet nie skompiluje ale poglądowo):

class Boo{
       void method{} // coś sobie tam robi
}

class BooService{
         Boo boo;//getters setters
         public BooService(Boo boo2){boo=boo2}
}

class BooTest{
         Boo boo;
         BooService booService; 
         @Before
         public void setUp(){
         booService = new BooService(boo);
         }

         @Test
          public void booTest(){
          booService.getBoo().method(); //Wywali NPE, bo boo nie zostało zainicjowane np boo=new Boo().
          //Oadnotowane @Mock spowodowałoby "zignorowanie" tej metody. NPE nie zostanie rzucone.
         }

}

2) Mówię, że trzeba najpierw stwo czyli:

@Before
public void setUp(){
   FooController fooController = new FooController(fooRepository);
} 

przy założeniu, że fooRepository jest mockowane.

3) Jeżeli testowana metoda wymaga mockowania (np, gdy chcesz zmockować fooRepository.findAll() tak, żeby zwracało jakąś shardkodowaną listę), bo np FooService gdzieś to wykorzystuje, to tak. 

Czemu Ci nie działa? 

CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);

To powinieneś postawić w setUp (metoda oadnotowana @Before). U Ciebie wywala NPE, bo w którymś miejscu w:

carRentalOptions.createNewCustomer(client);

wykorzystujesz coś co zwraca: carRentalStorageMock. Przed wywołaniem tej metody, musisz "powiedzieć" carRentalStorageMockowi, że jeżeli zostanie wywołana metoda carRentalStorageMock.getAllCustomers(), powinien zwrócić 

listOfClients

.W innym teście możesz powiedzieć, żeby przy wywołaniu tej metody zwrócił inną listę.

komentarz 14 sierpnia 2018 przez must Bywalec (2,980 p.)

Przed wywołaniem tej metody, musisz "powiedzieć" carRentalStorageMockowi, że jeżeli zostanie wywołana metoda carRentalStorageMock.getAllCustomers(), powinien zwrócić

A ja tego nie robie?

when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);

PS: W innej odpowiedzi dodałem cały kod testu i klasy testująćej.

0 głosów
odpowiedź 12 sierpnia 2018 przez Wiciorny Ekspert (270,170 p.)
  @Mock
    CarRentalStorage carRentalStorageMock;

gdzie jest inicjalizacja?

Generalnie informujesz - > ze jest to Mock, ale nie wprowadzasz inicjalizacji 

Być może w  twojej klasie testowej badana klasa powinna być opatrzona przypisami @InjectMocks. To mówi Mockito, do której klasy wstrzyknąć mocks:

@InjectMocks
private SomeManager someManager;

Od tego momentu możemy określić, które konkretne metody lub obiekty wewnątrz klasy, w tym przypadku SomeManager , zostaną zastąpione przez mocks:

@Mock
private SomeDependency someDependency;

W tym przykładzie, SomeDependency w klasie SomeManager będzie mokowane.https://stackoverflow.com/questions/16570029/mockito-mock-objects-returns-null/16570511

komentarz 13 sierpnia 2018 przez must Bywalec (2,980 p.)
@RunWith(MockitoJUnitRunner.class)
class CarRentalOptionsTest {

    @Mock
    CarRentalStorage carRentalStorageMock;
    @InjectMocks
    Client client;


    @Test
    void createNewCustomer() throws SQLException {
       // carRentalStorageMock = mock(CarRentalStorage.class);
        CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);

        List<Client> listOfClients = new ArrayList<Client>();
        listOfClients.add(client);

        when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);

        carRentalOptions.createNewCustomer(client);

        verify(carRentalStorageMock).addClient(client);


        assertEquals(1, listOfClients.size());
    }
}

O takie coś Ci chodzi?

komentarz 13 sierpnia 2018 przez must Bywalec (2,980 p.)

Dodałem jeszcze

@Before
public void setUp(){
    initMocks(this);
}

ale też nie działa :/

komentarz 13 sierpnia 2018 przez Mateusz Dąbrowski Użytkownik (700 p.)

@must,

1. rozmawianie o testowaniu jakiegoś kodu bez tego kodu - to tak jak kupowanie samochodu bez wcześniejszego oglądania go, można sobie porozmawiać, ale w zasadzie jaki to ma sens (wklej klasę którą testujesz, nie trzeba będzie zgadywać co robisz źle)

2. @RunWith(MockitoJUnitRunner.class) - runner stworzy wszystkie mocki dla klas, które są oznaczone adnotacją @Mock - nie trzeba używać @InjectMocks jeśli ustawiasz zależności przez konstruktor (ty to właśnie tak robisz)

3. @RunWith(MockitoJUnitRunner.class) używa się wymiennie z initMocks(this) nie ma sensu stosować tego razem bo robią to samo. initMocks(this) - używasz jak nie np chcesz użyć innego runnera pn. Springowego

4. napisałem w swoim życiu tysiące testów, więc oglądanie jakiegoś filmiku nie ma dla mnie sensu, jak pokażesz kod wszystko stanie się jasne. I to że u kogoś jest dobrze a u ciebie źle to może oznaczać że coś robisz inaczej.

5. umieszczanie when() przed wywołaniem metody, którą testujesz ma taki sens, że kod wykonuje się w określonej kolejności i tak po prostu jest. Mock jest zaślepką którą musisz sobie ustawić zanim jej użyjesz.

6. 

List<Client> listOfClients = new ArrayList<Client>();
listOfClients.add(client);
assertEquals(1, listOfClients.size());

To w twoim teście naprawdę nie ma sensu. Fakt tworzysz listę i na początku na ona size=0 później dodajesz element i size=1 i dalej już jej nie zmieniasz, więc twoja asercja ma zawsze stan true. 

Asercja powinna sprawdzać to co zwracasz z testowanej metody i wtedy ma szansę być true albo false.

komentarz 14 sierpnia 2018 przez Wiciorny Ekspert (270,170 p.)

2. @RunWith(MockitoJUnitRunner.class) - runner stworzy wszystkie mocki dla klas, które są oznaczone adnotacją @Mock - nie trzeba używać @InjectMocks jeśli ustawiasz zależności przez konstruktor (ty to właśnie tak robisz)

 A co jeśli twój obiekt @Mock zawiera w sobie inny obiekt, będący komponentem a niezbędny do działania? [ i dodatkowo ten mock ;] posiada Automatyczne wiązanie przez konstruktor... ale ... ty wywołujesz mocka tylko na obiekcie klasy?

Musisz dodać injectMock aby dowiązać do obiektu inny kontener 

Co do kodu się zgodzę trudno po omacku ... szczególnie gdy ktoś pisze już na wstępie zły test... bo nie robi tego w oparciu o Single Responsibility...  

komentarz 14 sierpnia 2018 przez must Bywalec (2,980 p.)

1234 Zgadzam się.

Tutaj jest klasa, którą testuję 

    private CarRentalStorage storage;

    CarRentalOptions(CarRentalStorage storage) {
        this.storage = storage;
    }

    void createNewCustomer(Client client) throws SQLException {
        storage.addClient(client);
    }

    void createNewCar(Car car) throws SQLException {
        storage.addNewCar(car);
    }

    void makeCarUnavailable(Car car) throws SQLException {
        storage.makeCarUnavailable(car);
    }

    void makeCarAvailable(Car car) throws SQLException {
        storage.makeCarAvailable(car);
    }

    void rentACar(RentingACar rentingACar) throws SQLException {
        storage.rentACar(rentingACar);
    }

    void populateTableViewCars(Car car) throws SQLException {
        storage.populateTableViewCars(car);
    }

    void populateTableRent(Client client) throws SQLException {
        storage.populateTableRent(client);
    }

    void getAllCustomers() throws SQLException {
        for (int i = 0; i < storage.getAllCustomers().size(); i++) {
            System.out.println("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());
            System.out.println("---------------------------");
        }
    }

    void returnACar(Car car) throws SQLException {
        storage.returnACar(car);
    }
}

Teraz mój test wygląda tak, co myślicie?

@RunWith(MockitoJUnitRunner.class)
class CarRentalOptionsTest {

    @Mock
    CarRentalStorage carRentalStorageMock;

    @Test
    void createNewCustomer() throws SQLException {
        carRentalStorageMock = mock(CarRentalStorage.class);
        CarRentalOptions carRentalOptions = new CarRentalOptions(carRentalStorageMock);
        Client client = new Client();

        List<Client> listOfClients = new ArrayList<Client>();
        listOfClients.add(client);
        when(carRentalStorageMock.getAllCustomers()).thenReturn(listOfClients);

        carRentalOptions.createNewCustomer(client);

        verify(carRentalStorageMock).addClient(client);

        assertTrue(carRentalStorageMock.getAllCustomers().contains(client));
    }
}

Tylko teraz lekko zgupiałem. Chcę przetestować jak nazwa metody wskazuje metodę createNewCustomer. 

Działa to na zasadzie po prostu dodawania z bazy danych. Aby to sprawdzić czy się dodało to muszę za pomocą carRentalStorageMock.getAllCustomers() a metoda ta tworzy listę wszystkich użytkowników w bazie danych czy ten użytkownik się tam znajduje.

I tutaj pojawia się problem, dlaczeog ja robie 

List<Client> listOfClients = new ArrayList<Client>();
listOfClients.add(client);

oraz

carRentalOptions.createNewCustomer(client);

bo teraz tworzę dwa razy użytkwoników. Dla mnie własnie najlogiczniejszym by było wywalenie carRentalOptions.createNewCustomer(client); przed when() i później to co w when i za pomocą assertTrue sprawdzenie czy ta lista zawiera tego użytwkonika czy nie.

Podobne pytania

0 głosów
1 odpowiedź 286 wizyt
pytanie zadane 17 kwietnia 2021 w Java przez Lulex Użytkownik (820 p.)
0 głosów
1 odpowiedź 160 wizyt
pytanie zadane 14 października 2019 w Java przez heartagram Obywatel (1,770 p.)
+1 głos
0 odpowiedzi 269 wizyt
pytanie zadane 11 sierpnia 2021 w Java przez Lulex Użytkownik (820 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 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

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy 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!

...