Problem z testami service

0

Hej jest mi ktoś w stanie wyjaśnić co może być nie tak z tymi testami?
Wszystkie inne działają a problem jest tylko z tymi z delete. Dodam, że metody usuwania byID i all działają dobrze w samej aplikacji natomiast w testach już nie.
W obu przypadkach jest:

org.opentest4j.AssertionFailedError: 
Expected :true
Actual   :false

czyli notatki istnieją po usunięciu.
Próbowałem już @Transactional jeśli ktoś to zaproponuje.

@Test
void shouldDeleteNoteById_Test() {
    Note note = new Note(1, LocalDate.now(), "testTitle", "testText");

    when(noteRepository.findById(1)).thenReturn(Optional.of(note));

    noteService.deleteById(note.getId());

    assertTrue(noteRepository.findById(note.getId()).isEmpty());

    verify(noteRepository, times(1)).findById(1);
    verify(noteRepository, times(1)).delete(note);

}

@Test
void shouldDeleteAllNotes_Test() {
    List<Note> mockNotes = Arrays.asList(
            new Note(1, LocalDate.now(), "testTitle", "testText"),
            new Note(2, LocalDate.now(), "testTitle11", "testText11")
    );

    when(noteRepository.findAll()).thenReturn(mockNotes);
    doNothing().when(noteRepository).deleteAll();

    noteService.deleteAllNotes();

    verify(noteRepository, times(1)).findAll();
    verify(noteRepository, times(1)).deleteAll();

    List<Note> noteList = noteRepository.findAll();

    assertTrue(noteList.isEmpty());
}
4

Tak pokrótce to wygląda jakbyś testował mocki.
noteRepository jest pewnie mockiem, więc musisz mu powiedzieć co ma robić, jak zostanie wywołane delete.
"By default" zwraca pewnie jakąś nie nullową wartość, sprawdź w debugu

3

Mockoza pospolita.

A jakby tak krok po kroku przeanalizować co robią te 4 linijki?

Note note = new Note(1, LocalDate.now(), "testTitle", "testText");
when(noteRepository.findById(1)).thenReturn(Optional.of(note));
noteService.deleteById(note.getId());
assertTrue(noteRepository.findById(note.getId()).isEmpty());

Bo jak na moje oko to najpierw mówisz, że noteRepository.findById(1) zawsze zwraca predefiniowaną notatkę, a później się dziwisz, że nie zwróciło pustego optionala ;)

0
Black007 napisał(a):

Tak pokrótce to wygląda jakbyś testował mocki.
noteRepository jest pewnie mockiem, więc musisz mu powiedzieć co ma robić, jak zostanie wywołane delete.
"By default" zwraca pewnie jakąś nie nullową wartość, sprawdź w debugu

no zwraca to samo co chce usunąć bo tego nie usuwa

some_ONE napisał(a):

Mockoza pospolita.

A jakby tak krok po kroku przeanalizować co robią te 4 linijki?

Note note = new Note(1, LocalDate.now(), "testTitle", "testText");
when(noteRepository.findById(1)).thenReturn(Optional.of(note));
noteService.deleteById(note.getId());
assertTrue(noteRepository.findById(note.getId()).isEmpty());

Bo jak na moje oko to najpierw mówisz, że noteRepository.findById(1) zawsze zwraca predefiniowaną notatkę, a później się dziwisz, że nie zwróciło pustego optionala ;)

No jest tworzony obiekt Note, później wywoływany jest findById i zwracany ten obiekt, nastepnie usuwanie za pomocą testowanej metody i na koniec sprawdzanie czy ten obiekt po usunięciu istnieje. No i wychodzi na to, że istnieje.

0

Ale co miałoby usunąć ten obiekt jeśli nie używasz prawdziwego obiektu który zawiera te dane tylko mocka któremu zawsze kazałeś zwracać ten obiekt?
Możesz pokazać resztę testów które działają i implementację noteRepository i noteService?
Testy na dodawanie / modyfikację niby Ci działają?

0
obscurity napisał(a):

Ale co miałoby usunąć ten obiekt jeśli nie używasz prawdziwego obiektu który zawiera te dane tylko mocka któremu zawsze kazałeś zwracać ten obiekt?
Możesz pokazać resztę testów które działają i implementację noteRepository i noteService?
Testy na dodawanie / modyfikację niby Ci działają?

@SpringBootTest
@AutoConfigureMockMvc
public class NoteServiceTest {
    @Mock
    private NoteRepository noteRepository;
    @InjectMocks
    private NoteServiceImpl noteService;

    @Test
    void shouldCreateNote_Test() {
        Note note = new Note(1, LocalDate.now(), "testTitle", "testText");

        when(noteRepository.save(note)).thenReturn(note);

        Note resultNote = noteService.createNote(note);

        assertEquals(note.getId(), resultNote.getId());
        assertEquals("testTitle", resultNote.getTitle());
        assertEquals("testText", resultNote.getText());

        verify(noteRepository, times(1)).save(note);
    }

    @Test
    void shouldFindNoteById_Test() {
        Note note = new Note(1, LocalDate.now(), "testTitle", "testText");

        when(noteRepository.findById(note.getId())).thenReturn(Optional.of(note));

        Note resultNote = noteService.getNoteById(note.getId());

        verify(noteRepository, times(1)).findById(note.getId());

        assertEquals(note, resultNote);
    }

    @Test
    void shouldFindAllNotes_Test() {
        List<Note> mockNotes = Arrays.asList(new Note(1, LocalDate.now(), "testTitle", "testText")
                , new Note(2, LocalDate.now(), "testTitle1", "testText1"));

        when(noteRepository.findAll()).thenReturn(mockNotes);

        List<Note> resultNotes = noteService.getAllNotes();

        verify(noteRepository, times(1)).findAll();

        assertIterableEquals(mockNotes, resultNotes);
    }
 @Test
    void shouldUpdateNote_Test() {
        Note existNote = new Note(1, LocalDate.now(), "testTitle", "testText");
        Note updatetNote = new Note(1, LocalDate.now(), "testTitleUpdate", "testTextUpdate");

        when(noteRepository.findById(existNote.getId())).thenReturn(Optional.of(existNote));
        when(noteRepository.save(existNote)).thenReturn(updatetNote);

        Note result = noteService.updateNote(existNote.getId(), updatetNote);

        assertEquals(updatetNote.getTitle(), result.getTitle());
        assertEquals(updatetNote.getText(), result.getText());
    }
@Service
public class NoteServiceImpl implements NoteService {
   private final NoteRepository noteRepository;

    @Autowired
    public NoteServiceImpl(NoteRepository noteRepository) {
        this.noteRepository = noteRepository;
    }

    @Override
    public Note createNote(Note note) {
        note.setDate(LocalDate.now());
        return noteRepository.save(note);
    }

    @Override
    public List<Note> getAllNotes() {
        List<Note> notes = noteRepository.findAll();
        if (notes.isEmpty()) {
            throw new EntityNotFoundException("List is empty");
        }
        return notes;
    }

    @Override
    public Note getNoteById(Integer id) {
        return noteRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Not found note"));
        
  @Override
    public void deleteAllNotes() {
       getAllNotes();
        noteRepository.deleteAll();
    }
    
    @Override
    public void deleteById(Integer id) {
        Note note = noteRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Note not found"));
        noteRepository.delete(note);
    }

    @Override
    public Note updateNote(Integer id, Note note) {
        Note presentNote = getNoteById(id);
        presentNote.setTitle(note.getTitle());
        presentNote.setText(note.getText());
        return noteRepository.save(presentNote);
    }
}

Kod pewnie nie jest wybitny pewnie ale no uczę się.

2

No więc oczywiście że te testy działają bo sprawdzasz dokładnie to co każesz im robić. Gdybyś w teście do tworzenia notek sprawdził czy notka jest zwracana przez findAll to już by nie zadziałało bo nie powiedziałeś mockowi że ma to zrobić.
Testujesz framework do mockowania zamiast swojego kodu, te testy są bezużyteczne.
Najlepiej by było gdybyś użył prawdziwe noteRepository i skierował je na jakąś bazę in memory albo nawet na prawdziwą. Mocków najlepiej nie używaj w ogóle.

0
obscurity napisał(a):

No więc oczywiście że te testy działają bo sprawdzasz dokładnie to co każesz im robić. Gdybyś w teście do tworzenia notek sprawdził czy notka jest zwracana przez findAll to już by nie zadziałało bo nie powiedziałeś mockowi że ma to zrobić.
Testujesz framework do mockowania zamiast swojego kodu, te testy są bezużyteczne.
Najlepiej by było gdybyś użył prawdziwe noteRepository i skierował je na jakąś bazę in memory albo nawet na prawdziwą. Mocków najlepiej nie używaj w ogóle.

Mam skonfigurowaną baze do testów h2 to mam użyć jej po prostu?
Tak to ma wyglądać?
Teraz działa ten test ale czy jest dobry?

@Test
void shouldDeleteNoteById_Test() {

  Note note = new Note(1, LocalDate.now(), "testTitle", "testText");

  noteRepository.save(note);

  noteService.deleteById(note.getId());

  assertTrue(noteRepository.findById(note.getId()).isEmpty());
  
}
2
LukaszCh233 napisał(a):

Mam skonfigurowaną baze do testów h2 to mam użyć jej po prostu?

Najlepiej użyj Testcontainers.

Edit.
Ja to bym odpalił skrypt SQL przed testem, który tworzyłby note.
Test wyglądałby tak:

@Test
void whenDeleteSuccess_NoteNotExist() {
    note.deleteById(1);
    assertFalse(noteChecker.noteExist(1));
}

Ewentualnie:

@Test
void whenDeleteSuccess_NoteNotExist() {
    int id = idFetcher.fetchNoteIdByTitle("title");
    note.deleteById(id);
    assertFalse(noteChecker.noteExist(id));
}
0
Ornstein napisał(a):
LukaszCh233 napisał(a):

Mam skonfigurowaną baze do testów h2 to mam użyć jej po prostu?

Najlepiej użyj Testcontainers.

Z tym bym tak nie przesadzał, bo takie testy są wolne.

PS: Chyba że posłużysz się jakąś strategią lub rozwiązaniem jak zrobić żeby były szybkie.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.