Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ dependencies {
// Test Dependencies
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:postgresql'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package de.tum.cit.memo;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;

@SpringBootTest
@ActiveProfiles("test")
@SuppressWarnings("resource")
public abstract class AbstractIntegrationTest {

private static final PostgreSQLContainer<?> POSTGRES =
new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("memo_test")
.withUsername("test")
.withPassword("test");

static {
POSTGRES.start();
}

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", POSTGRES::getJdbcUrl);
registry.add("spring.datasource.username", POSTGRES::getUsername);
registry.add("spring.datasource.password", POSTGRES::getPassword);
}
Comment thread
vtotalova marked this conversation as resolved.
Outdated
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package de.tum.cit.memo.repository;

import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;

@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@SuppressWarnings("resource")
public abstract class AbstractRepositoryTest {

private static final PostgreSQLContainer<?> POSTGRES =
new PostgreSQLContainer<>("postgres:16-alpine")
.withDatabaseName("memo_test")
.withUsername("test")
.withPassword("test");

static {
POSTGRES.start();
}

Comment thread
vtotalova marked this conversation as resolved.
Outdated
@Autowired
protected EntityManager entityManager;

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", POSTGRES::getJdbcUrl);
registry.add("spring.datasource.username", POSTGRES::getUsername);
registry.add("spring.datasource.password", POSTGRES::getPassword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package de.tum.cit.memo.repository;

import de.tum.cit.memo.entity.Competency;
import de.tum.cit.memo.util.IdGenerator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

@SuppressWarnings("null")
class CompetencyRepositoryTest extends AbstractRepositoryTest {

@Autowired
private CompetencyRepository competencyRepository;

@BeforeEach
void setUp() {
competencyRepository.deleteAll();
}
Comment thread
vtotalova marked this conversation as resolved.
Outdated

private Competency createCompetency(String title, String description) {
return Competency.builder()
.id(IdGenerator.generateCuid())
.title(title)
.description(description)
.build();
}

@Nested
@DisplayName("save")
class Save {

@Test
@DisplayName("should persist competency with all fields")
void shouldPersistCompetency() {
Competency competency = createCompetency("Java Programming", "Learn Java fundamentals");

Competency saved = competencyRepository.saveAndFlush(competency);
entityManager.refresh(saved);

assertThat(saved.getId()).isNotNull();
assertThat(saved.getTitle()).isEqualTo("Java Programming");
assertThat(saved.getDescription()).isEqualTo("Learn Java fundamentals");
assertThat(saved.getCreatedAt()).isNotNull();
}

@Test
@DisplayName("should persist competency without description")
void shouldPersistCompetencyWithoutDescription() {
Competency competency = createCompetency("Basic Competency", null);

Competency saved = competencyRepository.saveAndFlush(competency);
entityManager.refresh(saved);

assertThat(saved.getId()).isNotNull();
assertThat(saved.getTitle()).isEqualTo("Basic Competency");
assertThat(saved.getDescription()).isNull();
}

@Test
@DisplayName("should generate createdAt timestamp automatically")
void shouldGenerateCreatedAtTimestamp() {
Competency competency = createCompetency("Test Competency", "Description");

Competency saved = competencyRepository.saveAndFlush(competency);
entityManager.refresh(saved);

assertThat(saved.getCreatedAt()).isNotNull();
}
}

@Nested
@DisplayName("findById")
class FindById {

@Test
@DisplayName("should find existing competency by id")
void shouldFindExistingCompetency() {
Competency competency = createCompetency("Test Competency", "Test Description");
Competency saved = competencyRepository.save(competency);

Optional<Competency> found = competencyRepository.findById(saved.getId());

assertThat(found).isPresent();
assertThat(found.get().getTitle()).isEqualTo("Test Competency");
}

@Test
@DisplayName("should return empty for non-existent id")
void shouldReturnEmptyForNonExistentId() {
Optional<Competency> found = competencyRepository.findById("non-existent-id");

assertThat(found).isEmpty();
}
}

@Nested
@DisplayName("findRandomCompetencies")
class FindRandomCompetencies {

@Test
@DisplayName("should return requested number of random competencies")
void shouldReturnRequestedCount() {
for (int i = 0; i < 10; i++) {
competencyRepository.save(createCompetency("Competency " + i, "Description " + i));
}

List<Competency> random = competencyRepository.findRandomCompetencies(5);

assertThat(random).hasSize(5);
}

@Test
@DisplayName("should return all competencies when count exceeds total")
void shouldReturnAllWhenCountExceedsTotal() {
competencyRepository.save(createCompetency("Competency 1", "Description 1"));
competencyRepository.save(createCompetency("Competency 2", "Description 2"));

List<Competency> random = competencyRepository.findRandomCompetencies(10);

assertThat(random).hasSize(2);
}

@Test
@DisplayName("should return empty list when no competencies exist")
void shouldReturnEmptyWhenNoCompetencies() {
List<Competency> random = competencyRepository.findRandomCompetencies(5);

assertThat(random).isEmpty();
}
}

@Nested
@DisplayName("findAll")
class FindAll {

@Test
@DisplayName("should return all saved competencies")
void shouldReturnAllCompetencies() {
competencyRepository.save(createCompetency("Competency 1", "Description 1"));
competencyRepository.save(createCompetency("Competency 2", "Description 2"));
competencyRepository.save(createCompetency("Competency 3", "Description 3"));

List<Competency> all = competencyRepository.findAll();

assertThat(all).hasSize(3);
}

@Test
@DisplayName("should return empty list when no competencies exist")
void shouldReturnEmptyListWhenNoCompetencies() {
List<Competency> all = competencyRepository.findAll();

assertThat(all).isEmpty();
}
}

@Nested
@DisplayName("delete")
class Delete {

@Test
@DisplayName("should delete existing competency")
void shouldDeleteExistingCompetency() {
Competency competency = createCompetency("To Delete", "Will be deleted");
Competency saved = competencyRepository.save(competency);

competencyRepository.deleteById(saved.getId());

assertThat(competencyRepository.findById(saved.getId())).isEmpty();
}
}

@Nested
@DisplayName("update")
class Update {

@Test
@DisplayName("should update competency fields")
void shouldUpdateCompetencyFields() {
Competency competency = createCompetency("Original Title", "Original Description");
Competency saved = competencyRepository.save(competency);

saved.setTitle("Updated Title");
saved.setDescription("Updated Description");
Competency updated = competencyRepository.save(saved);

assertThat(updated.getTitle()).isEqualTo("Updated Title");
assertThat(updated.getDescription()).isEqualTo("Updated Description");
assertThat(updated.getId()).isEqualTo(saved.getId());
}
}
}
Loading