Problem z testami service

Problem z testami service
LukaszCh233
  • Rejestracja:prawie 2 lata
  • Ostatnio:dzień
  • Postów:180
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:

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

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

Kopiuj
@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());
}
edytowany 1x, ostatnio: Riddle
Black007
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 5 godzin
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


"Nie popełnia błędów tylko ten, kto nic nie robi"
SO
  • Rejestracja:ponad 10 lat
  • Ostatnio:około rok
3

Mockoza pospolita.

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

Kopiuj
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 ;)

LukaszCh233
  • Rejestracja:prawie 2 lata
  • Ostatnio:dzień
  • Postów:180
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?

Kopiuj
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.

edytowany 2x, ostatnio: Riddle
RequiredNickname
Nie istnieje. Ty nic z nikąd nie usuwasz bo nie masz skąd. Twoja "baza" to mock zaprogramowany by zawsze zwracać obiekt note gdy ktoś zawoła findById z jego id. Zamiast mocka zrób implementację in menory na bazie hashmapy lub h2 lub test containers.
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około 8 godzin
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ą?


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 2x, ostatnio: obscurity
LukaszCh233
  • Rejestracja:prawie 2 lata
  • Ostatnio:dzień
  • Postów:180
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ą?

Kopiuj
@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());
    }
Kopiuj
@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ę.

edytowany 1x, ostatnio: Riddle
Riddle
Dodawaj kolorowanie składni znacznikami ```java oraz ```.
PR
masz cały kontest webowy a używasz MockMVC?
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około 8 godzin
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.


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
LukaszCh233
  • Rejestracja:prawie 2 lata
  • Ostatnio:dzień
  • Postów:180
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?

Kopiuj
@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());
  
}
edytowany 1x, ostatnio: Riddle
Ornstein
  • Rejestracja:około 2 lata
  • Ostatnio:około 15 godzin
  • Postów:111
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:

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

Ewentualnie:

Kopiuj
@Test
void whenDeleteSuccess_NoteNotExist() {
    int id = idFetcher.fetchNoteIdByTitle("title");
    note.deleteById(id);
    assertFalse(noteChecker.noteExist(id));
}
edytowany 7x, ostatnio: Ornstein
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:minuta
  • Lokalizacja:Laska, z Polski
  • Postów:10085
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.

edytowany 1x, ostatnio: Riddle

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.