Piszę testy jednostkowe dla implementacji usługi, która używa repozytorium JPA - MessageRepository, która zwraca „Poszukiwany, ale nie wywołany: w rzeczywistości nie było żadnych interakcji z tym modelem”, gdy próbuję sprawdzić, czy jest wywoływany. Wyodrębniłem fragmenty kodu, aby uprościć wyjaśnienie problemu.

Wdrożenie usługi:

public class MessageServiceImpl {

  private final MessageRepository messageRepository;

  public MessageServiceImpl(MessageRepository messageRepository) {
    this.messageRepository = messageRepository;
  }

  public Message create(){
    Message result;        
    //some operations...
    Message message = new Message();
    message.setId(2L);
    message.setName("123231231");
    ...

    result = save(message);
    return  result;
  }

  public Message save(Message message){
    Message result = messageRepository.save(message); // returns a null when I debug while Testing
    return result;
  }

}

Klasa testów jednostkowych

@RunWith(SpringRunner.class)
public class MessageServiceImplUnitTest {

@Mock
MessageRepository messageRepository;

@Mock
OtherService otherService; // not a jpa repo but uses one in its implementation and works just as expected

@InjectMocks
MessageServiceImpl messageService;

Message message;

@Before
public void setup() {

    initMocks(this);
    message = new Message();
    message.setId(1L);
    message.setMessageDirection(MessageDirection.OUT);
}


// Unit Test for create method of MessageServiceImpl which should return a non-null Message Obj
@Test
public void createShouldReturnNotNullMessageObj(){

    // mocking save method to return the same Obj that was passed
    when(messageRepository.save(any(Message.class))).then(AdditionalAnswers.returnsFirstArg());

    Message result = messageService.create(); 

    // This fails and displays "Wanted but not invoked: Actually, there were 
    // zero interactions with this mock" 
    verify(messageRepository).save(any(Message.class));

    Assert.assertNotNull(result);
}

Nie mogę zrozumieć, dlaczego inne usługi pozorowane działają zgodnie z oczekiwaniami, ale repozytorium nie jest wywoływane. W rezultacie obiekt Message Obj jest zwracany jako null z save (Message message) obj.

0
USQ91 21 listopad 2019, 09:21

2 odpowiedzi

Usuń @SpringBootTest(classes = Abc.class): to test jednostkowy, a nie test integracji.

Usuń @Autowired: używasz iniekcji konstruktora.

Usuń messageService = new MessageServiceImpl(messageRepository);: adnotacje Mockito robią to za Ciebie, a ponieważ masz initMocks() po tej instrukcji, messageRepository i tak jest nadal pusty.

Usuń RunWith(MockitoJUnitRunner.class), ponieważ dzwonisz pod numer initMocks() wyraźnie w swoim kodzie.

1
JB Nizet 21 listopad 2019, 09:54
Wprowadziłem zmiany, wciąż ten sam rezultat. Chyba nie rozumiem, na co wskazujesz.
 – 
USQ91
21 listopad 2019, 09:47
Dodałem jeszcze jedną rzecz, którą musisz usunąć.
 – 
JB Nizet
21 listopad 2019, 09:54
Testy nadal kończą się niepowodzeniem z dokładnie tym samym błędem. Nie mogę zrozumieć dlaczego.
 – 
USQ91
21 listopad 2019, 10:03
Zamieść pełną reprodukcję, w której wystarczy skopiować i wkleić Twój kod. Kiedy to robię, twój test zdał. Więc jest coś, czego nie wiemy.
 – 
JB Nizet
21 listopad 2019, 10:14

Używasz @InjectMocks na swojej zmiennej messageService. I zainicjuj go w samym konstruktorze.

Zrób jedno z nich, a nie oba, przypuszczam, że na tym polega twój problem. @InjectMock inicjalizuje twój obiekt i wstrzykuje makiety za ciebie. Jeśli to zrobisz i ręcznie zainicjujesz obiekt, wyniki mogą być nieprzewidywalne.

Twoje okablowanie jest również wyłączone, używasz inicjalizacji konstruktora, ale masz adnotację @Autowired na polu, przenieś ją do konstruktora.

Masz również adnotację SpringBootTest na szczycie swojej klasy, która nie jest konieczna do testu jednostkowego.

0
Thihara 21 listopad 2019, 09:39
Bawiłem się wokół @InjectMocks, a także robiłem to w konfiguracji, aby sprawdzić, czy to może zadziałać. Utrzymanie obu nie ma znaczenia. To wciąż zawodzi
 – 
USQ91
21 listopad 2019, 09:43
Co się stanie, gdy naprawisz okablowanie, usuniesz @InjectMocks?
 – 
Thihara
21 listopad 2019, 09:46
To było przez pomyłkę. Nie miałem autowiringu w moim oryginalnym kodzie. Naprawiłem to tutaj
 – 
USQ91
21 listopad 2019, 09:48
To były jedyne oczywiste błędy, jakie widziałem.
 – 
Thihara
21 listopad 2019, 09:51
Usunięcie @InjectMocks i zamiast tego ręczne inicjowanie obj w setip również nie ma znaczenia, nadal nie działa
 – 
USQ91
21 listopad 2019, 09:52