I got the following class with which I want to test my repository:
package de.gabriel.vertretungsplan.repositories;
import de.gabriel.vertretungsplan.models.Fach;
import de.gabriel.vertretungsplan.models.Klasse;
import de.gabriel.vertretungsplan.models.StundenplanEintrag;
import de.gabriel.vertretungsplan.models.Tag;
import de.gabriel.vertretungsplan.models.enums.Anwesenheit;
import de.gabriel.vertretungsplan.models.enums.Rolle;
import de.gabriel.vertretungsplan.models.enums.Tage;
import de.gabriel.vertretungsplan.models.users.Lehrer;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DataJpaTest
@ActiveProfiles("test")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StundenplanEintragRepositoryTest {
@Autowired
private StundenplanEintragRepository stundenplanEintragRepository;
@Autowired
private KlasseRepository klasseRepository;
@Autowired
private FachRepository fachRepository;
@Autowired
private LehrerRepository lehrerRepository;
@Autowired
private TagRepository tagRepository;
private Lehrer deutschLehrer;
private Tag montag;
private StundenplanEintrag stundenplanEintragReference;
@BeforeAll
void init() {
Klasse klasse6a = new Klasse("6a");
klasseRepository.saveAll(List.of(
klasse6a
));
Fach deutsch = new Fach("Deutsch", "DE");
fachRepository.saveAll(List.of(
deutsch
));
deutschLehrer = new Lehrer("deutschLehrer", "deutschLehrer", Rolle.getPrefixedRolle(Rolle.LEHRER), Anwesenheit.ANWESEND);
deutschLehrer.setFaecher(List.of(deutsch));
lehrerRepository.saveAll(List.of(
deutschLehrer
));
montag = new Tag(Tage.MONTAG);
tagRepository.saveAll(List.of(
montag
));
stundenplanEintragReference = new StundenplanEintrag(1, klasse6a, deutsch, deutschLehrer, montag);
stundenplanEintragRepository.saveAll(List.of(
stundenplanEintragReference
));
}
@AfterAll
void tearDown() {
stundenplanEintragRepository.deleteAll();
}
@Test
@DisplayName("Check if correct Stundenplan Eintrag is returned given Lehrer [deutschLehrer] and Tag [montag]")
void findByLehrerAndTag() {
List<StundenplanEintrag> stundenplanEintrag = stundenplanEintragRepository.findByLehrerAndTag(deutschLehrer, montag);
assertThat(stundenplanEintrag.get(0).getId()).isEqualTo(stundenplanEintragReference.getId());
}
@Test
@DisplayName("Check if correct Stundenplan Eintrag is returned given Lehrer [deutschLehrer]")
void findByLehrer() {
List<StundenplanEintrag> stundenplanEintrag = stundenplanEintragRepository.findByLehrer(deutschLehrer);
assertThat(stundenplanEintrag.get(0).getLehrer().getUsername()).isEqualTo(deutschLehrer.getUsername());
}
}
As you can see currently I am comparing the result from the repository by a single field with the reference object (like the id
or username
), because if I compare them like this:
@Test
@DisplayName("Check if correct Stundenplan Eintrag is returned given Lehrer [deutschLehrer] and Tag [montag]")
void findByLehrerAndTag() {
List<StundenplanEintrag> stundenplanEintrag = stundenplanEintragRepository.findByLehrerAndTag(deutschLehrer, montag);
assertThat(stundenplanEintrag.get(0)).isEqualTo(stundenplanEintragReference);
}
@Test
@DisplayName("Check if correct Stundenplan Eintrag is returned given Lehrer [deutschLehrer]")
void findByLehrer() {
List<StundenplanEintrag> stundenplanEintrag = stundenplanEintragRepository.findByLehrer(deutschLehrer);
assertThat(stundenplanEintrag.get(0).getLehrer()).isEqualTo(deutschLehrer);
}
the tests fail because the adress of the actual objects differ from the "expected" objects adress even if they are "the same" objects.
Expected :de.gabriel.vertretungsplan.models.StundenplanEintrag@38d895e8
Actual :de.gabriel.vertretungsplan.models.StundenplanEintrag@1b897ffb
I understand that it gets a new adress in memory (wrong as pointed out in the comments, it's the hash code). I want to know if it is a good practice to compare by something like the id
or how else you would solve this or if there is a better practice to compare the object returned by a repository with the originally saved object? (And I still want to be able to save the entity only once in the @BeforeAll
annotated method)
Generally I see nothing bad in comparison IDs in the test. It's pretty obvious that you operate with records and assert if it's the same record (the same record has the same ID).
As an option, of course, you may consider to make your solution more complex and override equals()
(and hashCode()
) methods of your class. It will make the solution more elegant, so you encapsulate in the class the definition of "being the same". You can define field(s) that needs to be equal in order to consider the objects as equal.
I do not think there is a "right" answer to your question. It depends... Check the discussions on the Internet and get the idea in which situations you want to override equals
and in which situations you don't. Here are the couple of such a discussions:
As I said, for the start, I'd probably compare IDs and not go the path of overriding, especially if you're not feeling confident with that.