Commit fcdc7394 authored by Georgi Cholev's avatar Georgi Cholev
Browse files

Merge branch 'junit-lecture' into 'main'

Add unit tests Services

See merge request paysafe-interns-valentin-2023/paysafe-interns-valentin-martin/student-managment/georgi-cholev-student-management-2023!4
parents 77c8728f 67d2d59d
1 merge request!4Add unit tests Services
Showing with 1000 additions and 88 deletions
+1000 -88
.gradle
.idea
build
......@@ -246,7 +246,7 @@ public class ConsoleAppRunner implements AppRunner {
this.setUpFunc(counter++, "Add new course", "{name}/{totalHours}", this::addNewCourse);
this.setUpFunc(counter++, "Add new student", "{name}/{age}", this::addNewStudent);
this.setUpFunc(counter++, "Add new teacher", "{name}/{degree} -> (Master, Bachelor, Doctorate)", this::addNewTeacher);
this.setUpFunc(counter++, "Add new teacher", "{name}/{degree} -> (MSc, BSc, PHD)", this::addNewTeacher);
this.setUpFunc(counter++, "Add a teacher to a specific course", "{courseId}/{teacherId}", this::addTeacherToCourse);
this.setUpFunc(counter++, "Remove a teacher from a specific course", "{courseId}", this::removeTeacherFromCourse);
this.setUpFunc(counter++, "Add a student to a specific course", "{courseId}/{studentId}", this::addStudentToCourse);
......
......@@ -14,7 +14,7 @@ repositories {
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2")
}
tasks.named<Test>("test") {
......
......@@ -6,4 +6,5 @@ dependencies {
implementation(project(":models"))
implementation(project(":data"))
testImplementation("org.mockito:mockito-core:5.4.0")
}
package student.management.core.constants;
public class Messages {
private Messages() {
}
public static final String NULL_ENTITY = "No information as required to create entity.";
public static final String TEACHER_NOT_FOUND_FORMAT = "A teacher with ID: %d is not found.";
public static final String TEACHER_WITH_NAME_DEGREE_NOT_CREATED = "A teacher with %s and %s cannot be created.";
public static final String GRADE_NOT_FOUND_FORMAT = "A grade with ID: %d is not found.";
public static final String GRADE_NOT_IN_RANGE = "Grade must be between 2.0 and 6.0.";
public static final String STUDENT_NOT_FOUND_FORMAT = "A student with ID: %d is not found.";
public static final String STUDENT_WITH_NAME_AGE_NOT_CREATED = "A student with %s and %d cannot be created.";
public static final String COURSE_NOT_FOUND_FORMAT = "A course with ID: %d is not found.";
public static final String COURSE_WITH_NAME_TOTAL_HOURS_NOT_CREATED = "A course with %s and %d cannot be created.";
public static final String TEACHER_LEADS_COURSE_FORMAT = "Teacher: %s now leads %s.";
public static final String TEACHER_NOT_LEAD_COURSE_FORMAT = "Course: %s now does not have a teacher.";
public static final String STUDENT_ATTENDS_COURSE_FORMAT = "Student: %s now attends %s";
public static final String CONFLICTING_STUDENT_COURSE_PAIR = "Student: %s is not enrolled in Course: %s";
public static final String STUDENT_EARNED_GRADE_FOR_COURSE = "Student: %s has earned a grade %.1f for Course: %s.";
}
......@@ -8,10 +8,12 @@ import student.management.models.dtos.response_dto.AvgGradeForStudentsInCourses;
import student.management.models.dtos.response_dto.CourseResponseDto;
import student.management.models.dtos.response_dto.CourseWithAvgGrade;
import student.management.models.dtos.response_dto.CourseWithTeacherStudentsResponseDto;
import student.management.models.entities.Course;
import java.util.List;
public interface CourseService {
Course findById(Long id) throws UnidentifiableEntityException;
CourseResponseDto create(CourseCreateDto dto) throws InvalidEntityArgumentsException;
......
package student.management.core.services;
import student.management.models.dtos.response_dto.GradeResponseDto;
import student.management.models.entities.Grade;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
......@@ -7,6 +8,6 @@ import student.management.models.dtos.create_dto.GradeCreateDto;
public interface GradeService {
Grade create(GradeCreateDto dto) throws InvalidEntityArgumentsException;
Grade findById(Long id) throws UnidentifiableEntityException;
GradeResponseDto create(GradeCreateDto dto) throws InvalidEntityArgumentsException;
}
package student.management.core.services;
import student.management.models.dtos.response_dto.StudentResponseDto;
import student.management.models.dtos.response_dto.StudentWithAvgGrade;
import student.management.models.dtos.response_dto.StudentWithCourseAvgGrade;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
import student.management.models.dtos.create_dto.StudentCreateDto;
......@@ -9,8 +9,11 @@ import student.management.models.entities.Student;
public interface StudentService {
StudentResponseDto create(StudentCreateDto dto) throws InvalidEntityArgumentsException;
Student findById(Long id) throws UnidentifiableEntityException;
StudentResponseDto create(StudentCreateDto dto) throws InvalidEntityArgumentsException;
void addGradeFor(Long id, Long gradeId) throws UnidentifiableEntityException;
StudentWithAvgGrade getStudentWithAvgGrade(Long studentId) throws UnidentifiableEntityException;
StudentWithCourseAvgGrade getStudentWithAvgGrade(Long studentId) throws UnidentifiableEntityException;
}
......@@ -8,7 +8,8 @@ import student.management.models.entities.Teacher;
public interface TeacherService {
Teacher findById(Long id) throws UnidentifiableEntityException;
TeacherResponseDto create(TeacherCreateDto dto) throws InvalidEntityArgumentsException;
Teacher findById(Long id) throws UnidentifiableEntityException;
}
......@@ -8,6 +8,7 @@ import student.management.core.services.StudentService;
import student.management.core.services.TeacherService;
import student.management.data.repositories.CourseRepository;
import student.management.models.dtos.create_dto.GradeCreateDto;
import student.management.models.dtos.response_dto.GradeResponseDto;
import student.management.models.entities.Course;
import student.management.models.entities.Grade;
import student.management.core.services.CourseService;
......@@ -18,12 +19,16 @@ import student.management.models.dtos.response_dto.AvgGradeForStudentsInCourses;
import student.management.models.dtos.response_dto.CourseResponseDto;
import student.management.models.dtos.response_dto.CourseWithAvgGrade;
import student.management.models.dtos.response_dto.CourseWithTeacherStudentsResponseDto;
import student.management.models.dtos.response_dto.StudentWithAvgGrade;
import student.management.models.dtos.response_dto.StudentWithCourseAvgGrade;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static student.management.core.constants.Messages.*;
public class CourseServiceImpl implements CourseService {
private final CourseRepository courseRepository;
......@@ -38,11 +43,17 @@ public class CourseServiceImpl implements CourseService {
this.gradeService = gradeService;
}
public Course findById(Long id) throws UnidentifiableEntityException {
return this.courseRepository
.findById(id)
.orElseThrow(
() -> new UnidentifiableEntityException(COURSE_NOT_FOUND_FORMAT)
);
}
@Override
public CourseResponseDto create(CourseCreateDto dto) throws InvalidEntityArgumentsException {
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException("A course with " + dto.name() + " and " + dto.totalHours() + " cannot be created");
}
throwIfInvalid(dto);
Course course = new Course(dto);
this.courseRepository.save(course);
......@@ -57,14 +68,14 @@ public class CourseServiceImpl implements CourseService {
course.setTeacher(teacher);
return "Teacher " + teacher.getName() + " now leads " + course.getName();
return String.format(TEACHER_LEADS_COURSE_FORMAT, teacher.getName(), course.getName());
}
@Override
public String removeTeacherFor(Long courseId) throws UnidentifiableEntityException {
Course course = this.findById(courseId);
course.removeTeacher();
return "Course: " + course.getName() + " now des not have a teacher.";
return String.format(TEACHER_NOT_LEAD_COURSE_FORMAT, course.getName());
}
@Override
......@@ -74,35 +85,43 @@ public class CourseServiceImpl implements CourseService {
course.addStudent(student);
return "Student " + student.getName() + " now attends " + course.getName();
return String.format(STUDENT_ATTENDS_COURSE_FORMAT, student.getName(), course.getName());
}
@Override
public String addGradeForStudentIn(Long courseId, Long studentId, Double gradeValue) throws UnidentifiableEntityException, InvalidEntityArgumentsException, ConflictingRequestParametersException {
public String addGradeForStudentIn(Long courseId, Long studentId, Double gradeValue)
throws UnidentifiableEntityException, InvalidEntityArgumentsException, ConflictingRequestParametersException {
Course course = this.findById(courseId);
Student student = this.studentService.findById(studentId);
if (!course.containsStudent(student)) {
throw new ConflictingRequestParametersException("Student " + student.getId() + " is not enrolled in Course " + course.getId());
throw new ConflictingRequestParametersException(
String.format(CONFLICTING_STUDENT_COURSE_PAIR, student.getName(), course.getName())
);
}
Grade grade = this.gradeService.create(new GradeCreateDto(gradeValue));
this.studentService.addGradeFor(studentId, grade.getId());
GradeResponseDto gradeResponseDto = this.gradeService.create(new GradeCreateDto(gradeValue));
Grade grade = this.gradeService.findById(gradeResponseDto.id());
this.studentService.addGradeFor(studentId, gradeResponseDto.id());
course.addGrade(grade);
return "Student " + student.getName() + " has earned a grade " + grade.getValue() + " for Course " + course.getName();
return String.format(STUDENT_EARNED_GRADE_FOR_COURSE, student.getName(), grade.getValue(), course.getName());
}
@Override
public AvgGradeForStudentsInCourses findCoursesByNameAsc_WithStudentsAvgGradeAsc() {
Map<String, Set<StudentWithAvgGrade>> map = new LinkedHashMap<>();
this.courseRepository.findAllByNameAsc()
Map<String, Set<StudentWithCourseAvgGrade>> map = new LinkedHashMap<>();
Collection<Course> allByNameAsc = this.courseRepository.findAllByNameAsc();
allByNameAsc
.forEach(course ->
map.computeIfAbsent(course.getName(), k -> new TreeSet<>())
.addAll(
course.getStudents()
.stream()
.map(getStudentWithAvgGrade(course))
.filter(s -> s.avgGrade() != 0.0)
.collect(Collectors.toSet())
));
return new AvgGradeForStudentsInCourses(map);
......@@ -120,37 +139,45 @@ public class CourseServiceImpl implements CourseService {
@Override
public CourseWithAvgGrade findAvgGradeFor(Long courseId) throws UnidentifiableEntityException {
Course course = this.findById(courseId);
double avgGrade =
Double.parseDouble(
String.format("%.2f", course.getGrades()
.stream()
.mapToDouble(Grade::getValue)
.average()
.orElse(0.0)));
double avgGrade = getAvgGrade(course.getGrades());
return new CourseWithAvgGrade(courseId, course.getName(), avgGrade);
}
private Function<Student, StudentWithAvgGrade> getStudentWithAvgGrade(Course course) {
private Function<Student, StudentWithCourseAvgGrade> getStudentWithAvgGrade(Course course) {
return student -> {
Set<Grade> grades = new HashSet<>(course.getGrades());
grades.retainAll(student.getGrades());
double avgGrade = Double.parseDouble(
String.format("%.2f",
grades.stream()
.mapToDouble(Grade::getValue)
.average()
.orElse(0.0)));
return new StudentWithAvgGrade(student.getId(), student.getName(), avgGrade);
double avgGrade = getAvgGrade(grades);
return new StudentWithCourseAvgGrade(student.getId(), student.getName(), avgGrade);
};
}
private Course findById(Long id) throws UnidentifiableEntityException {
return this.courseRepository.findById(id)
.orElseThrow(() -> new UnidentifiableEntityException("A course with ID: " + id + " is not found."));
private static double getAvgGrade(Set<Grade> grades) {
return BigDecimal.valueOf(
grades.stream()
.mapToDouble(Grade::getValue)
.average()
.orElse(0.0)).setScale(1, RoundingMode.HALF_EVEN)
.doubleValue();
}
private void throwIfInvalid(CourseCreateDto dto) throws InvalidEntityArgumentsException {
if (dto == null) {
throw new InvalidEntityArgumentsException(NULL_ENTITY);
}
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException(
String.format(COURSE_WITH_NAME_TOTAL_HOURS_NOT_CREATED, dto.name(), dto.totalHours())
);
}
}
private boolean hasInvalidArguments(CourseCreateDto dto) {
return (dto.name().isBlank()) || (dto.totalHours() <= 0);
return (dto.name() == null || dto.totalHours() == null) ||
(dto.name().isBlank() || dto.name().length() == 1) ||
dto.totalHours() <= 0;
}
}
package student.management.core.services.impl;
import student.management.core.services.GradeService;
import student.management.models.dtos.response_dto.GradeResponseDto;
import student.management.models.entities.Grade;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
import student.management.data.repositories.GradeRepository;
import student.management.models.dtos.create_dto.GradeCreateDto;
import static student.management.core.constants.Messages.*;
public class GradeServiceImpl implements GradeService {
private final GradeRepository gradeRepository;
......@@ -16,23 +19,35 @@ public class GradeServiceImpl implements GradeService {
}
@Override
public Grade create(GradeCreateDto dto) throws InvalidEntityArgumentsException {
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException("Grade must be between 2.0 and 6.0");
}
public Grade findById(Long id) throws UnidentifiableEntityException {
return this.gradeRepository
.findById(id)
.orElseThrow(
() -> new UnidentifiableEntityException(String.format(GRADE_NOT_FOUND_FORMAT, id))
);
}
@Override
public GradeResponseDto create(GradeCreateDto dto) throws InvalidEntityArgumentsException {
throwIfInvalid(dto);
Grade grade = new Grade(dto);
this.gradeRepository.save(grade);
return grade;
return new GradeResponseDto(grade.getId(), grade.getValue());
}
@Override
public Grade findById(Long id) throws UnidentifiableEntityException {
return this.gradeRepository.findById(id)
.orElseThrow(() -> new UnidentifiableEntityException("Grade with ID: " + id + " not found."));
private void throwIfInvalid(GradeCreateDto dto) throws InvalidEntityArgumentsException {
if (dto == null) {
throw new InvalidEntityArgumentsException(NULL_ENTITY);
}
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException(GRADE_NOT_IN_RANGE);
}
}
private boolean hasInvalidArguments(GradeCreateDto dto) {
return dto.value() < 2.0 || dto.value() > 6.0;
return dto.value() == null || dto.value() < 2.0 || dto.value() > 6.0;
}
}
package student.management.core.services.impl;
import student.management.models.dtos.response_dto.StudentResponseDto;
import student.management.models.dtos.response_dto.StudentWithAvgGrade;
import student.management.models.dtos.response_dto.StudentWithCourseAvgGrade;
import student.management.models.entities.Grade;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
......@@ -11,6 +11,11 @@ import student.management.data.repositories.StudentRepository;
import student.management.models.dtos.create_dto.StudentCreateDto;
import student.management.models.entities.Student;
import java.math.BigDecimal;
import java.math.RoundingMode;
import static student.management.core.constants.Messages.*;
public class StudentServiceImpl implements StudentService {
private final StudentRepository studentRepository;
......@@ -21,11 +26,17 @@ public class StudentServiceImpl implements StudentService {
this.gradeService = gradeService;
}
@Override
public Student findById(Long id) throws UnidentifiableEntityException {
return this.studentRepository.findById(id)
.orElseThrow(
() -> new UnidentifiableEntityException(String.format(STUDENT_NOT_FOUND_FORMAT, id))
);
}
@Override
public StudentResponseDto create(StudentCreateDto dto) throws InvalidEntityArgumentsException {
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException("A student with " + dto.name() + " and " + dto.age() + " cannot be created");
}
throwIfInvalid(dto);
Student student = new Student(dto);
this.studentRepository.save(student);
......@@ -33,12 +44,6 @@ public class StudentServiceImpl implements StudentService {
return new StudentResponseDto(student);
}
@Override
public Student findById(Long id) throws UnidentifiableEntityException {
return this.studentRepository.findById(id)
.orElseThrow(() -> new UnidentifiableEntityException("A student with ID: " + id + " is not found"));
}
@Override
public void addGradeFor(Long id, Long gradeId) throws UnidentifiableEntityException {
Grade grade = this.gradeService.findById(gradeId);
......@@ -47,19 +52,36 @@ public class StudentServiceImpl implements StudentService {
}
@Override
public StudentWithAvgGrade getStudentWithAvgGrade(Long studentId) throws UnidentifiableEntityException {
public StudentWithCourseAvgGrade getStudentWithAvgGrade(Long studentId) throws UnidentifiableEntityException {
Student student = this.findById(studentId);
double avgGrade = Double.parseDouble(
String.format("%.2f", student.getGrades()
.stream()
.mapToDouble(Grade::getValue)
.average()
.orElse(0.0)));
return new StudentWithAvgGrade(studentId, student.getName(), avgGrade);
double avgGrade =
BigDecimal.valueOf(
student.getGrades()
.stream()
.mapToDouble(Grade::getValue)
.average()
.orElse(0.0)
).setScale(1, RoundingMode.HALF_EVEN)
.doubleValue();
return new StudentWithCourseAvgGrade(studentId, student.getName(), avgGrade);
}
private void throwIfInvalid(StudentCreateDto dto) throws InvalidEntityArgumentsException {
if (dto == null) {
throw new InvalidEntityArgumentsException(NULL_ENTITY);
}
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException(
String.format(STUDENT_WITH_NAME_AGE_NOT_CREATED, dto.name(), dto.age())
);
}
}
private boolean hasInvalidArguments(StudentCreateDto dto) {
return (dto.age() < 0 || dto.age() > 80) || (dto.name().isBlank());
return (dto.age() == null || dto.name() == null) ||
(dto.age() < 5 || dto.age() > 80) ||
(dto.name().isBlank() || dto.name().length() == 1);
}
}
......@@ -9,6 +9,8 @@ import student.management.models.dtos.create_dto.TeacherCreateDto;
import student.management.models.entities.Teacher;
import student.management.models.enums.DegreeType;
import static student.management.core.constants.Messages.*;
public class TeacherServiceImpl implements TeacherService {
private final TeacherRepository teacherRepository;
......@@ -17,24 +19,39 @@ public class TeacherServiceImpl implements TeacherService {
this.teacherRepository = teacherRepository;
}
@Override
public Teacher findById(Long id) throws UnidentifiableEntityException {
return this.teacherRepository
.findById(id)
.orElseThrow(
() -> new UnidentifiableEntityException(String.format(TEACHER_NOT_FOUND_FORMAT, id))
);
}
@Override
public TeacherResponseDto create(TeacherCreateDto dto) throws InvalidEntityArgumentsException {
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException("A teacher with " + dto.name() + " and " + dto.degreeLabel() + " cannot be created");
}
throwIfInvalid(dto);
Teacher teacher = new Teacher(dto);
this.teacherRepository.save(teacher);
return new TeacherResponseDto(teacher);
}
@Override
public Teacher findById(Long id) throws UnidentifiableEntityException {
return this.teacherRepository.findById(id)
.orElseThrow(() -> new UnidentifiableEntityException("A teacher with ID: " + id + " is not found."));
private void throwIfInvalid(TeacherCreateDto dto) throws InvalidEntityArgumentsException {
if (dto == null) {
throw new InvalidEntityArgumentsException(NULL_ENTITY);
}
if (hasInvalidArguments(dto)) {
throw new InvalidEntityArgumentsException(
String.format(TEACHER_WITH_NAME_DEGREE_NOT_CREATED, dto.name(), dto.degreeLabel())
);
}
}
private boolean hasInvalidArguments(TeacherCreateDto dto) {
return (DegreeType.getTypeByLabel(dto.degreeLabel()) == null) || (dto.name().isBlank());
return (DegreeType.getTypeByLabel(dto.degreeLabel()) == null) ||
(dto.name() == null || dto.name().isBlank() || dto.name().length() == 1);
}
}
package student.management.core.services_test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import student.management.core.exceptions.ConflictingRequestParametersException;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
import student.management.core.services.CourseService;
import student.management.core.services.GradeService;
import student.management.core.services.StudentService;
import student.management.core.services.TeacherService;
import student.management.core.services.impl.CourseServiceImpl;
import student.management.data.repositories.CourseRepository;
import student.management.models.dtos.create_dto.CourseCreateDto;
import student.management.models.dtos.create_dto.GradeCreateDto;
import student.management.models.dtos.create_dto.StudentCreateDto;
import student.management.models.dtos.create_dto.TeacherCreateDto;
import student.management.models.dtos.response_dto.CourseResponseDto;
import student.management.models.dtos.response_dto.CourseWithAvgGrade;
import student.management.models.dtos.response_dto.CourseWithTeacherStudentsResponseDto;
import student.management.models.dtos.response_dto.GradeResponseDto;
import student.management.models.dtos.response_dto.StudentWithCourseAvgGrade;
import student.management.models.entities.Course;
import student.management.models.entities.Grade;
import student.management.models.entities.Student;
import student.management.models.entities.Teacher;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static student.management.core.constants.Messages.COURSE_NOT_FOUND_FORMAT;
import static student.management.core.constants.Messages.COURSE_WITH_NAME_TOTAL_HOURS_NOT_CREATED;
import static student.management.core.constants.Messages.NULL_ENTITY;
public class CourseServiceTest {
private static CourseRepository mockedCourseRepository;
private static GradeService mockedGradeService;
private static StudentService mockedStudentService;
private static TeacherService mockedTeacherService;
private static CourseService courseService;
private CourseCreateDto courseCreateDto;
private Course course;
private CourseResponseDto courseResponseDto;
@BeforeAll
static void setUp() {
mockedCourseRepository = mock(CourseRepository.class);
mockedGradeService = mock(GradeService.class);
mockedStudentService = mock(StudentService.class);
mockedTeacherService = mock(TeacherService.class);
courseService = new CourseServiceImpl(mockedCourseRepository, mockedTeacherService,
mockedStudentService, mockedGradeService);
}
@BeforeEach
void initializeCourseEntity() {
courseCreateDto = new CourseCreateDto("Math", 120);
course = new Course(courseCreateDto);
courseResponseDto = new CourseResponseDto(course);
}
@Test
@DisplayName("Get by Id returns expected Course")
void getCourseById_ReturnsExpected() throws UnidentifiableEntityException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
Course byId = courseService.findById(course.getId());
assertSame(course.getId(), byId.getId());
assertSame(course.getName(), byId.getName());
assertSame(course.getTotalHours(), byId.getTotalHours());
}
@Test
@DisplayName("Get by Invalid Id throws exception")
void getGradeByInvalidId_Throws() {
doReturn(Optional.empty())
.when(mockedCourseRepository)
.findById(-1L);
assertThrows(
UnidentifiableEntityException.class,
() -> courseService.findById(-1L),
String.format(COURSE_NOT_FOUND_FORMAT, -1L)
);
}
@Test
@DisplayName("Create Course returns expected Dto")
void createGrade_ReturnsExpectedDto() throws InvalidEntityArgumentsException {
CourseResponseDto actualDto = courseService.create(courseCreateDto);
assertEquals(courseResponseDto.getName(), actualDto.getName());
assertEquals(courseResponseDto.getTotalHours(), actualDto.getTotalHours());
}
@Test
@DisplayName("Create Course with invalid parameters throws")
void createGradeWithInvalidParams_Throws() {
CourseCreateDto invalidCourse = new CourseCreateDto(null, -120);
assertThrows(
InvalidEntityArgumentsException.class,
() -> courseService.create(invalidCourse),
String.format(COURSE_WITH_NAME_TOTAL_HOURS_NOT_CREATED, invalidCourse.name(), invalidCourse.totalHours())
);
}
@Test
@DisplayName("Create Course with null Dto throws")
void createCourseWithNullDto_Throws() {
assertThrows(
InvalidEntityArgumentsException.class,
() -> courseService.create(null),
NULL_ENTITY
);
}
@Test
@DisplayName("Add Teacher to existing Course successful")
void addTeacherToExistingCourse_Successful() throws UnidentifiableEntityException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
Teacher teacher = new Teacher(new TeacherCreateDto("Smith", "phd"));
doReturn(teacher)
.when(mockedTeacherService)
.findById(anyLong());
courseService.addTeacherTo(course.getId(), teacher.getId());
assertEquals(course.getTeacher().getId(), teacher.getId());
}
@Test
@DisplayName("Remove Teacher to existing Course successful")
void removeTeacherToExistingCourse_Successful() throws UnidentifiableEntityException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
Teacher teacher = new Teacher(new TeacherCreateDto("Smith", "phd"));
course.setTeacher(teacher);
courseService.removeTeacherFor(course.getId());
assertNull(course.getTeacher());
}
@Test
@DisplayName("Add Student to existing Course successful")
void addStudentToExistingCourse_Successful() throws UnidentifiableEntityException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
Student student = new Student(new StudentCreateDto("Pepi", 15));
doReturn(student)
.when(mockedStudentService)
.findById(anyLong());
courseService.addStudentTo(course.getId(), student.getId());
assertTrue(course.getStudents().contains(student));
}
@Test
@DisplayName("Add grade for Student enrolled in Course successful")
void addGradeForStudentEnrolledInCourse_Successful() throws UnidentifiableEntityException, InvalidEntityArgumentsException, ConflictingRequestParametersException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
Student student = new Student(new StudentCreateDto("Pepi", 15));
course.addStudent(student);
doReturn(student)
.when(mockedStudentService)
.findById(anyLong());
Grade grade = new Grade(new GradeCreateDto(4.5));
doReturn(new GradeResponseDto(grade.getId(), grade.getValue()))
.when(mockedGradeService)
.create(any(GradeCreateDto.class));
doReturn(grade)
.when(mockedGradeService)
.findById(anyLong());
courseService.addGradeForStudentIn(course.getId(), student.getId(), 4.5);
assertTrue(course.getGrades().contains(grade));
}
@Test
@DisplayName("Add grade for Student not enrolled in Course throws")
void addGradeForStudentNotEnrolledInCourse_Throws() throws UnidentifiableEntityException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
Student student = new Student(new StudentCreateDto("Pepi", 15));
doReturn(student)
.when(mockedStudentService)
.findById(anyLong());
assertThrows(
ConflictingRequestParametersException.class,
() -> courseService.addGradeForStudentIn(course.getId(), student.getId(), 4.5)
);
}
@Test
@DisplayName("Show in right order Courses by name Asc with students Avg grade Asc")
void showInRightOrder_CoursesByNameAscWithStudentsAvgGradeAsc() {
Course course1 = new Course(new CourseCreateDto("English", 120));
arrangeCoursesWithStudentsAndGrades(course, course1);
doReturn(Set.of(course1, course))
.when(mockedCourseRepository)
.findAllByNameAsc();
Map<String, Set<StudentWithCourseAvgGrade>> actualOrder =
courseService.findCoursesByNameAsc_WithStudentsAvgGradeAsc()
.avgGradeForStudentsInCourses();
assertTrue(areInAscOrder(actualOrder.keySet()));
assertTrue(studentAreInAscByAvgGrade(actualOrder.values()));
}
private static void arrangeCoursesWithStudentsAndGrades(Course course0, Course course1) {
Student student0 = new Student(new StudentCreateDto("Pepi", 15));
Student student1 = new Student(new StudentCreateDto("Niki", 15));
Student student2 = new Student(new StudentCreateDto("Maria", 15));
Student student3 = new Student(new StudentCreateDto("Ivana", 15));
course0.addStudent(student0);
course0.addStudent(student2);
course0.addStudent(student3);
course1.addStudent(student0);
course1.addStudent(student1);
Grade grade0 = new Grade(new GradeCreateDto(4.5));
Grade grade1 = new Grade(new GradeCreateDto(5.5));
Grade grade2 = new Grade(new GradeCreateDto(3.7));
Grade grade3 = new Grade(new GradeCreateDto(2.6));
student2.addGrades(List.of(grade0, grade1));
student3.addGrades(List.of(grade2, grade3));
course0.addGrades(List.of(grade0, grade1, grade2, grade3));
grade0 = new Grade(new GradeCreateDto(6.0));
grade1 = new Grade(new GradeCreateDto(5.35));
grade2 = new Grade(new GradeCreateDto(2.0));
grade3 = new Grade(new GradeCreateDto(5.89));
student0.addGrades(List.of(grade0, grade1));
student1.addGrades(List.of(grade2, grade3));
course1.addGrades(List.of(grade0, grade1, grade2, grade3));
}
private boolean studentAreInAscByAvgGrade(Collection<Set<StudentWithCourseAvgGrade>> values) {
return values.stream()
.filter(this::areInAscOrder)
.count() == values.size();
}
private <T extends Comparable<T>> boolean areInAscOrder(Collection<T> values) {
if (values.size() <= 1) {
return true;
}
Iterator<T> itr = values.iterator();
T previous = itr.next();
T current;
while (itr.hasNext()) {
current = itr.next();
if (previous.compareTo(current) > 0) {
return false;
}
previous = current;
}
return true;
}
@Test
@DisplayName("Show all courses and their teachers and students")
void showCoursesWithTeacherAndStudents() {
Course course1 = new Course(new CourseCreateDto("English", 120));
arrangeCoursesWithStudentsAndTeachers(course, course1);
doReturn(List.of(course, course1))
.when(mockedCourseRepository)
.findAll();
List<CourseWithTeacherStudentsResponseDto> actualAll = courseService.findAll();
assertEquals(2, actualAll.size());
assertNotNull(actualAll.get(0).getTeacher());
assertNull(actualAll.get(1).getTeacher());
assertEquals(2, actualAll.get(0).getStudents().size());
assertEquals(1, actualAll.get(1).getStudents().size());
}
private void arrangeCoursesWithStudentsAndTeachers(Course course0, Course course1) {
Student student0 = new Student(new StudentCreateDto("Pepi", 12));
Student student1 = new Student(new StudentCreateDto("Mimi", 12));
course0.setTeacher(new Teacher(new TeacherCreateDto("Ivanova", "msc")));
course0.addStudent(student0);
course0.addStudent(student1);
course1.addStudent(student0);
}
@Test
@DisplayName("Show the average grade for all students in a specific course")
void showAvgGradeForAllStudents() throws UnidentifiableEntityException {
course.addGrades(List.of(
new Grade(new GradeCreateDto(3.0)),
new Grade(new GradeCreateDto(4.0)),
new Grade(new GradeCreateDto(5.0)),
new Grade(new GradeCreateDto(6.0))
));
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
CourseWithAvgGrade actual = courseService.findAvgGradeFor(course.getId());
assertEquals(4.5, actual.avgGrade());
assertEquals(course.getId(), actual.id());
assertEquals(course.getName(), actual.name());
}
@Test
@DisplayName("Show the average grade for all students in a specific course when It has no grades is 0")
void showAvgGradeForAllStudentsWhenNone_IsZero() throws UnidentifiableEntityException {
doReturn(Optional.of(course))
.when(mockedCourseRepository)
.findById(anyLong());
CourseWithAvgGrade actual = courseService.findAvgGradeFor(course.getId());
assertEquals(0.0, actual.avgGrade());
assertEquals(course.getId(), actual.id());
assertEquals(course.getName(), actual.name());
}
}
package student.management.core.services_test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
import student.management.core.services.GradeService;
import student.management.core.services.impl.GradeServiceImpl;
import student.management.data.repositories.GradeRepository;
import student.management.models.dtos.create_dto.GradeCreateDto;
import student.management.models.dtos.response_dto.GradeResponseDto;
import student.management.models.entities.Grade;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static student.management.core.constants.Messages.GRADE_NOT_FOUND_FORMAT;
import static student.management.core.constants.Messages.GRADE_NOT_IN_RANGE;
import static student.management.core.constants.Messages.NULL_ENTITY;
public class GradeServiceTest {
private static GradeRepository mockedGradeRepository;
private static GradeService gradeService;
private GradeCreateDto gradeCreateDto;
private Grade grade;
private GradeResponseDto gradeResponseDto;
@BeforeAll
static void setUp() {
mockedGradeRepository = mock(GradeRepository.class);
gradeService = new GradeServiceImpl(mockedGradeRepository);
}
@BeforeEach
void initializeGrade() {
gradeCreateDto = new GradeCreateDto(4.5);
grade = new Grade(gradeCreateDto);
gradeResponseDto = new GradeResponseDto(grade.getId(), grade.getValue());
}
@Test
@DisplayName("Get by Id returns expected Grade")
void getGradeById_ReturnsExpected() throws UnidentifiableEntityException {
doReturn(Optional.of(grade))
.when(mockedGradeRepository)
.findById(anyLong());
Grade byId = gradeService.findById(grade.getId());
assertSame(grade.getId(), byId.getId());
assertSame(grade.getValue(), byId.getValue());
}
@Test
@DisplayName("Get by Invalid Id throws exception")
void getGradeByInvalidId_Throws() {
doReturn(Optional.empty())
.when(mockedGradeRepository)
.findById(anyLong());
assertThrows(
UnidentifiableEntityException.class,
() -> gradeService.findById(-1L),
String.format(GRADE_NOT_FOUND_FORMAT, -1L)
);
}
@Test
@DisplayName("Create Grade returns expected Dto")
void createGrade_ReturnsExpectedDto() throws InvalidEntityArgumentsException {
GradeResponseDto actualDto = gradeService.create(gradeCreateDto);
assertEquals(gradeResponseDto.value(), actualDto.value());
}
@Test
@DisplayName("Create Grade with value outside 2.0 - 6.0")
void createGradeWithInvalidParams_Throws() {
GradeCreateDto invalidGrade = new GradeCreateDto(1.0);
assertThrows(
InvalidEntityArgumentsException.class,
() -> gradeService.create(invalidGrade),
GRADE_NOT_IN_RANGE
);
}
@Test
@DisplayName("Create Grade with null Dto throws")
void createGradeWithNullDto_Throws() {
assertThrows(
InvalidEntityArgumentsException.class,
() -> gradeService.create(null),
NULL_ENTITY
);
}
}
package student.management.core.services_test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
import student.management.core.services.GradeService;
import student.management.core.services.StudentService;
import student.management.core.services.impl.StudentServiceImpl;
import student.management.data.repositories.StudentRepository;
import student.management.models.dtos.create_dto.GradeCreateDto;
import student.management.models.dtos.create_dto.StudentCreateDto;
import student.management.models.dtos.response_dto.StudentResponseDto;
import student.management.models.dtos.response_dto.StudentWithCourseAvgGrade;
import student.management.models.entities.Grade;
import student.management.models.entities.Student;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static student.management.core.constants.Messages.NULL_ENTITY;
import static student.management.core.constants.Messages.STUDENT_NOT_FOUND_FORMAT;
import static student.management.core.constants.Messages.STUDENT_WITH_NAME_AGE_NOT_CREATED;
public class StudentServiceTest {
private static StudentRepository mockedStudentRepository;
private static GradeService mockedGradeService;
private static StudentService studentService;
private StudentCreateDto studentCreateDto;
private Student student;
private StudentResponseDto studentResponseDto;
@BeforeAll
static void setUp() {
mockedStudentRepository = mock(StudentRepository.class);
mockedGradeService = mock(GradeService.class);
studentService = new StudentServiceImpl(mockedStudentRepository, mockedGradeService);
}
@BeforeEach
void initializeStudent() {
studentCreateDto = new StudentCreateDto("Pepi", 15);
student = new Student(studentCreateDto);
studentResponseDto = new StudentResponseDto(student);
}
@Test
@DisplayName("Get by Id returns expected Student")
void getGradeById_ReturnsExpected() throws UnidentifiableEntityException {
doReturn(Optional.of(student))
.when(mockedStudentRepository)
.findById(anyLong());
Student byId = studentService.findById(student.getId());
assertSame(student.getId(), byId.getId());
assertSame(student.getAge(), byId.getAge());
}
@Test
@DisplayName("Get by Invalid Id throws exception")
void getGradeByInvalidId_Throws() {
doReturn(Optional.empty())
.when(mockedStudentRepository)
.findById(anyLong());
assertThrows(
UnidentifiableEntityException.class,
() -> studentService.findById(-1L),
String.format(STUDENT_NOT_FOUND_FORMAT, -1L));
}
@Test
@DisplayName("Create Student returns expected Dto")
void createStudent_ReturnsExpectedDto() throws InvalidEntityArgumentsException {
StudentResponseDto actualDto = studentService.create(studentCreateDto);
assertEquals(studentResponseDto.getName(), actualDto.getName());
assertEquals(studentResponseDto.getAge(), actualDto.getAge());
}
@Test
@DisplayName("Create Student with invalid parameters throws")
void createStudentWithInvalidParams_Throws() {
StudentCreateDto invalidStudent = new StudentCreateDto("a", -1);
assertThrows(
InvalidEntityArgumentsException.class,
() -> studentService.create(invalidStudent),
String.format(STUDENT_WITH_NAME_AGE_NOT_CREATED, invalidStudent.name(), invalidStudent.age())
);
}
@Test
@DisplayName("Create Student with null Dto throws")
void createStudentWithNullDto_Throws() {
assertThrows(
InvalidEntityArgumentsException.class,
() -> studentService.create(null),
NULL_ENTITY
);
}
@Test
@DisplayName("Add existing Grade to existing Student is successful")
void addExistingGrade_ToExistingStudent_Successful() throws UnidentifiableEntityException {
Grade grade = new Grade(new GradeCreateDto(3.3));
doReturn(grade)
.when(mockedGradeService)
.findById(anyLong());
doReturn(Optional.of(student))
.when(mockedStudentRepository)
.findById(anyLong());
studentService.addGradeFor(0L, 0L);
assertTrue(student.getGrades().contains(grade));
}
@Test
@DisplayName("Add Grade to not existing Student throws")
void addExistingGrade_ToNotExistingStudent_Throws() throws UnidentifiableEntityException {
Grade grade = new Grade(new GradeCreateDto(3.3));
doReturn(grade)
.when(mockedGradeService)
.findById(anyLong());
doReturn(Optional.empty())
.when(mockedStudentRepository)
.findById(anyLong());
assertThrows(
UnidentifiableEntityException.class,
() -> studentService.addGradeFor(0L, -1L),
String.format(STUDENT_NOT_FOUND_FORMAT, -1L));
}
@ParameterizedTest
@ValueSource(strings = {
"2.0/3.0/4.0/5.0/6.0",
"2.05/3.5444/4.22225/5.145",
"5",
"5/6"
})
@DisplayName("Get Student With Average Grade Successful")
void getStudentWithAvgGrade_Successful(String gradesSeparated) throws UnidentifiableEntityException {
doReturn(Optional.of(student))
.when(mockedStudentRepository)
.findById(anyLong());
addGradesToStudent(gradesSeparated);
double expectedAvg = getExpectedAvg(gradesSeparated);
StudentWithCourseAvgGrade actualStudent = studentService.getStudentWithAvgGrade(student.getId());
assertEquals(student.getId(), actualStudent.id());
assertEquals(student.getName(), actualStudent.name());
assertEquals(expectedAvg, actualStudent.avgGrade());
}
private double getExpectedAvg(String gradesSeparated) {
return BigDecimal.valueOf(
Arrays.stream(gradesSeparated.split("/"))
.mapToDouble(Double::parseDouble)
.average()
.orElse(0.0)
).setScale(1, RoundingMode.HALF_EVEN)
.doubleValue();
}
private void addGradesToStudent(String gradesSeparated) {
Arrays.stream(gradesSeparated.split("/"))
.map(g -> new Grade(new GradeCreateDto(Double.parseDouble(g))))
.forEach(g -> student.addGrade(g));
}
@Test
@DisplayName("Get Student With Average Grade When It has no grades is 0")
void getStudentWithAvgGrade_WithNoGrades_IsZero() throws UnidentifiableEntityException {
doReturn(Optional.of(student))
.when(mockedStudentRepository)
.findById(anyLong());
StudentWithCourseAvgGrade actualStudent = studentService.getStudentWithAvgGrade(0L);
assertEquals(0.0, actualStudent.avgGrade());
}
}
package student.management.core.services_test;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import student.management.core.exceptions.InvalidEntityArgumentsException;
import student.management.core.exceptions.UnidentifiableEntityException;
import student.management.core.services.TeacherService;
import student.management.core.services.impl.TeacherServiceImpl;
import student.management.data.repositories.TeacherRepository;
import student.management.models.dtos.create_dto.TeacherCreateDto;
import student.management.models.dtos.response_dto.TeacherResponseDto;
import student.management.models.entities.Teacher;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static student.management.core.constants.Messages.NULL_ENTITY;
import static student.management.core.constants.Messages.TEACHER_NOT_FOUND_FORMAT;
import static student.management.core.constants.Messages.TEACHER_WITH_NAME_DEGREE_NOT_CREATED;
class TeacherServiceTest {
private static TeacherRepository mockedTeacherRepository = mock(TeacherRepository.class);
private static TeacherService teacherService = new TeacherServiceImpl(mockedTeacherRepository);
private TeacherCreateDto teacherCreateDto;
private Teacher teacher;
private TeacherResponseDto teacherResponseDto;
@BeforeAll
static void setUp() {
mockedTeacherRepository = mock(TeacherRepository.class);
teacherService = new TeacherServiceImpl(mockedTeacherRepository);
}
@BeforeEach
void initializeTeacher() {
teacherCreateDto = new TeacherCreateDto("Anna", "BSc");
teacher = new Teacher(teacherCreateDto);
teacherResponseDto = new TeacherResponseDto(teacher);
}
@Test
@DisplayName("Get by Id returns expected Teacher")
void getTeacherById_ReturnsExpected() throws UnidentifiableEntityException {
doReturn(Optional.of(teacher))
.when(mockedTeacherRepository)
.findById(anyLong());
Teacher byId = teacherService.findById(teacher.getId());
assertSame(teacher.getId(), byId.getId());
assertSame(teacher.getName(), byId.getName());
assertSame(teacher.getDegreeType(), byId.getDegreeType());
}
@Test
@DisplayName("Get by Invalid Id throws exception")
void getTeacherByInvalidId_Throws() {
doReturn(Optional.empty())
.when(mockedTeacherRepository)
.findById(anyLong());
assertThrows(
UnidentifiableEntityException.class,
() -> teacherService.findById(-1L),
String.format(TEACHER_NOT_FOUND_FORMAT, -1L));
}
@Test
@DisplayName("Create Teacher returns expected Dto")
void createTeacher_ReturnsExpectedDto() throws InvalidEntityArgumentsException {
TeacherResponseDto actualDto = teacherService.create(teacherCreateDto);
assertEquals(teacherResponseDto.getName(), actualDto.getName());
assertEquals(teacherResponseDto.getDegree(), actualDto.getDegree());
}
@Test
@DisplayName("Create Teacher with invalid parameters throws")
void createTeacherWithInvalidParams_Throws() {
TeacherCreateDto invalidTeacher = new TeacherCreateDto(null, null);
assertThrows(
InvalidEntityArgumentsException.class,
() -> teacherService.create(invalidTeacher),
String.format(TEACHER_WITH_NAME_DEGREE_NOT_CREATED, invalidTeacher.name(), invalidTeacher.degreeLabel())
);
}
@Test
@DisplayName("Create Teacher with null Dto throws")
void createTeacherWithNullDto_Throws() {
assertThrows(
InvalidEntityArgumentsException.class,
() -> teacherService.create(null),
NULL_ENTITY
);
}
}
......@@ -4,5 +4,4 @@ plugins {
dependencies {
implementation(project(":models"))
}
......@@ -8,7 +8,7 @@ import java.util.Set;
public interface CourseRepository extends EntityRepository<Course> {
Set<Course> findAllByNameAsc();
Collection<Course> findAllByNameAsc();
Collection<Course> findAll();
}
......@@ -4,28 +4,27 @@ import student.management.data.repositories.CourseRepository;
import student.management.models.entities.Course;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
public class CourseRepositoryInMemoryImpl implements CourseRepository {
private final Map<Long, Course> coursesById;
private final Set<Course> coursesByNameAsc;
public CourseRepositoryInMemoryImpl() {
this.coursesById = new HashMap<>();
this.coursesByNameAsc = new TreeSet<>();
}
@Override
public void save(Course course) {
this.coursesById.put(course.getId(), course);
this.coursesByNameAsc.add(course);
}
@Override
......@@ -36,8 +35,12 @@ public class CourseRepositoryInMemoryImpl implements CourseRepository {
}
@Override
public Set<Course> findAllByNameAsc() {
return this.coursesByNameAsc;
public Collection<Course> findAllByNameAsc() {
return this.coursesById
.values()
.stream()
.sorted()
.toList();
}
@Override
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment