diff options
Diffstat (limited to 'src')
6 files changed, 354 insertions, 42 deletions
diff --git a/src/main/java/com/stileeducation/markr/entity/TestResult.java b/src/main/java/com/stileeducation/markr/entity/TestResult.java index cb7cea5..0d68f62 100644 --- a/src/main/java/com/stileeducation/markr/entity/TestResult.java +++ b/src/main/java/com/stileeducation/markr/entity/TestResult.java @@ -8,6 +8,16 @@ import java.util.Objects; @Table(name = "test_results") public class TestResult { + public TestResult() { + } + + public TestResult(Long id, Student student, Test test, Integer marksAwarded) { + this.id = id; + this.student = student; + this.test = test; + this.marksAwarded = marksAwarded; + } + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/src/main/java/com/stileeducation/markr/service/TestResultsService.java b/src/main/java/com/stileeducation/markr/service/TestResultsService.java index 8d1b314..95b42f3 100644 --- a/src/main/java/com/stileeducation/markr/service/TestResultsService.java +++ b/src/main/java/com/stileeducation/markr/service/TestResultsService.java @@ -7,16 +7,18 @@ import com.stileeducation.markr.entity.TestResult; import com.stileeducation.markr.repository.StudentRepository; import com.stileeducation.markr.repository.TestRepository; import com.stileeducation.markr.repository.TestResultRepository; +import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation; +import org.apache.commons.math3.stat.descriptive.rank.Percentile; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; @Service public class TestResultsService { + public static final boolean IS_BIAS_CORRECTED = false; @Autowired private TestResultRepository testResultRepository; @@ -78,68 +80,64 @@ public class TestResultsService { .orElse(0.0); } - public double calculateStandardDeviationOfTestResults(List<TestResult> results, double mean) { + public double calculateStandardDeviationOfTestResults(List<TestResult> results) { if (results.isEmpty()) { - return 0.0; // or throw an exception if no results are found + return 0.0; } + double[] marks = + results.stream() + .mapToDouble(TestResult::getMarksAwarded) + .toArray(); - // Calculate the variance - double variance = results.stream() - .mapToDouble(result -> Math.pow(result.getMarksAwarded() - mean, 2)) - .average() - .orElse(0.0); - - // Return the standard deviation - return Math.sqrt(variance); + StandardDeviation standardDeviation = new StandardDeviation(IS_BIAS_CORRECTED); + return standardDeviation.evaluate(marks); } - public double calculatePercentile(List<Integer> sortedMarks, double percentile) { - if (sortedMarks.isEmpty()) { + public double calculate25thPercentile(List<TestResult> results) { + if (results.isEmpty()) { return 0.0; } - int index = (int) Math.floor(percentile / 100.0 * sortedMarks.size()) - 1; - return sortedMarks.get(Math.min(index, sortedMarks.size() - 1)); + double[] marks = + results.stream() + .mapToDouble(TestResult::getMarksAwarded) + .toArray(); + return new Percentile().evaluate(marks, 25.0); } - public List<Integer> getSortedMarks(List<TestResult> testResults) { - return testResults.stream() - .map(TestResult::getMarksAwarded) - .sorted() - .collect(Collectors.toList()); - } - - public double calculate25thPercentile(List<Integer> sortedMarks) { - return calculatePercentile(sortedMarks, 25.0); - } - - public double calculate50thPercentile(List<Integer> sortedMarks) { - return calculatePercentile(sortedMarks, 50.0); + public double calculate50thPercentile(List<TestResult> results) { + if (results.isEmpty()) { + return 0.0; + } + double[] marks = + results.stream() + .mapToDouble(TestResult::getMarksAwarded) + .toArray(); + return new Percentile().evaluate(marks, 50.0); } - public double calculate75thPercentile(List<Integer> sortedMarks) { - return calculatePercentile(sortedMarks, 75.0); + public double calculate75thPercentile(List<TestResult> results) { + if (results.isEmpty()) { + return 0.0; + } + double[] marks = + results.stream() + .mapToDouble(TestResult::getMarksAwarded) + .toArray(); + return new Percentile().evaluate(marks, 75.0); } public AggregatedTestResultsDTO aggregateTestResults(String testId) { List<TestResult> testResults = findAllByTestId(testId); - List<Integer> sortedMarks = getSortedMarks(testResults); AggregatedTestResultsDTO results = new AggregatedTestResultsDTO(); results.setMean(calculateMeanOfTestResults(testResults)); - - results.setStddev(calculateStandardDeviationOfTestResults(testResults, results.getMean())); - + results.setStddev(calculateStandardDeviationOfTestResults(testResults)); results.setMin(calculateMinOfTestResults(testResults)); - results.setMax(calculateMaxOfTestResults(testResults)); - - results.setP25(calculate25thPercentile(sortedMarks)); - - results.setP50(calculate50thPercentile(sortedMarks)); - - results.setP75(calculate75thPercentile(sortedMarks)); - + results.setP25(calculate25thPercentile(testResults)); + results.setP50(calculate50thPercentile(testResults)); + results.setP75(calculate75thPercentile(testResults)); results.setCount(testResults.size()); return results; diff --git a/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java b/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java new file mode 100644 index 0000000..474d731 --- /dev/null +++ b/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java @@ -0,0 +1,175 @@ +package com.stileeducation.markr.service; + +import com.stileeducation.markr.entity.Student; +import com.stileeducation.markr.entity.TestResult; +import com.stileeducation.markr.repository.StudentRepository; +import com.stileeducation.markr.repository.TestRepository; +import com.stileeducation.markr.repository.TestResultRepository; +import com.stileeducation.markr.util.StudentBuilder; +import com.stileeducation.markr.util.TestBuilder; +import com.stileeducation.markr.util.TestResultBuilder; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +class TestResultsServiceTest { + + private static Student student1; + private static Student student2; + private static Student student3; + private static Student student4; + + private static com.stileeducation.markr.entity.Test test1; + + private static TestResult testResult1; + private static TestResult testResult2; + private static TestResult testResult3; + private static TestResult testResult4; + private static TestResult testResult5; + private static TestResult testResult6; + + private static List<TestResult> test1Results; + + @Mock + private TestResultRepository testResultRepository; + + @Mock + private StudentRepository studentRepository; + + @Mock + private TestRepository testRepository; + + @InjectMocks + private TestResultsService testResultsService; + + @BeforeAll + static void setupTestData() { + student1 = new StudentBuilder() + .withId(1L) + .withStudentNumber("555123") + .withFirstName("Emily") + .withLastName("Clark") + .build(); + + student2 = new StudentBuilder() + .withId(2L) + .withStudentNumber("555456") + .withFirstName("James") + .withLastName("Taylor") + .build(); + + student3 = new StudentBuilder() + .withId(3L) + .withStudentNumber("555789") + .withFirstName("Sophia") + .withLastName("Martinez") + .build(); + + student4 = new StudentBuilder() + .withId(4L) + .withStudentNumber("555012") + .withFirstName("Liam") + .withLastName("Anderson") + .build(); + + test1 = new TestBuilder() + .withId(1L) + .withTestId("1234") + .withMarksAvailable(100) + .build(); + + testResult1 = new TestResultBuilder() + .withStudent(student1) + .withTest(test1) + .withMarksAwarded(10) + .build(); + + testResult2 = new TestResultBuilder() + .withStudent(student2) + .withTest(test1) + .withMarksAwarded(20) + .build(); + + testResult3 = new TestResultBuilder() + .withStudent(student3) + .withTest(test1) + .withMarksAwarded(40) + .build(); + + testResult4 = new TestResultBuilder() + .withStudent(student4) + .withTest(test1) + .withMarksAwarded(50) + .build(); + + testResult5 = new TestResultBuilder() + .withStudent(student3) + .withTest(test1) + .withMarksAwarded(70) + .build(); + + testResult6 = new TestResultBuilder() + .withStudent(student4) + .withTest(test1) + .withMarksAwarded(80) + .build(); + + test1Results = List.of(testResult1, testResult2, testResult3, testResult4, testResult5, testResult6); + } + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void calculateMeanOfTestResults() { + double mean = testResultsService.calculateMeanOfTestResults(test1Results); + assertEquals(45.0, mean, 0.01); + } + + @Test + void calculateMinOfTestResults() { + double min = testResultsService.calculateMinOfTestResults(test1Results); + assertEquals(10.0, min, 0.01); + } + + @Test + void calculateMaxOfTestResults() { + double max = testResultsService.calculateMaxOfTestResults(test1Results); + assertEquals(80.0, max, 0.01); + } + + @Test + void calculateStandardDeviationOfTestResults() { + double standardDeviationOfTestResults = testResultsService.calculateStandardDeviationOfTestResults(test1Results); + assertEquals(25, standardDeviationOfTestResults, 0.01); + } + + @Test + void calculate25thPercentile() { + double percentile = testResultsService.calculate25thPercentile(test1Results); + assertEquals(17.5, percentile, 0.01); + } + + @Test + void calculate50thPercentile() { + double percentile = testResultsService.calculate50thPercentile(test1Results); + assertEquals(45, percentile, 0.01); + } + + @Test + void calculate75thPercentile() { + double percentile = testResultsService.calculate75thPercentile(test1Results); + assertEquals(72.5, percentile, 0.01); + } + +}
\ No newline at end of file diff --git a/src/test/java/com/stileeducation/markr/util/StudentBuilder.java b/src/test/java/com/stileeducation/markr/util/StudentBuilder.java new file mode 100644 index 0000000..5189f19 --- /dev/null +++ b/src/test/java/com/stileeducation/markr/util/StudentBuilder.java @@ -0,0 +1,50 @@ +package com.stileeducation.markr.util; + +import com.stileeducation.markr.entity.Student; +import com.stileeducation.markr.entity.TestResult; + +import java.util.HashSet; +import java.util.Set; + +public class StudentBuilder { + private Long id; + private String firstName; + private String lastName; + private String studentNumber; + private Set<TestResult> testResults = new HashSet<>(); + + public StudentBuilder withId(Long id) { + this.id = id; + return this; + } + + public StudentBuilder withFirstName(String firstName) { + this.firstName = firstName; + return this; + } + + public StudentBuilder withLastName(String lastName) { + this.lastName = lastName; + return this; + } + + public StudentBuilder withStudentNumber(String studentNumber) { + this.studentNumber = studentNumber; + return this; + } + + public StudentBuilder withTestResults(Set<TestResult> testResults) { + this.testResults = testResults; + return this; + } + + public Student build() { + Student student = new Student(); + student.setId(id); + student.setFirstName(firstName); + student.setLastName(lastName); + student.setStudentNumber(studentNumber); + student.setTestResults(testResults); + return student; + } +}
\ No newline at end of file diff --git a/src/test/java/com/stileeducation/markr/util/TestBuilder.java b/src/test/java/com/stileeducation/markr/util/TestBuilder.java new file mode 100644 index 0000000..5c513f3 --- /dev/null +++ b/src/test/java/com/stileeducation/markr/util/TestBuilder.java @@ -0,0 +1,43 @@ +package com.stileeducation.markr.util; + +import com.stileeducation.markr.entity.Test; +import com.stileeducation.markr.entity.TestResult; + +import java.util.HashSet; +import java.util.Set; + +public class TestBuilder { + private Long id; + private String testId; + private Integer marksAvailable; + private Set<TestResult> testResults = new HashSet<>(); + + public TestBuilder withId(Long id) { + this.id = id; + return this; + } + + public TestBuilder withTestId(String testId) { + this.testId = testId; + return this; + } + + public TestBuilder withMarksAvailable(Integer marksAvailable) { + this.marksAvailable = marksAvailable; + return this; + } + + public TestBuilder withTestResults(Set<TestResult> testResults) { + this.testResults = testResults; + return this; + } + + public Test build() { + Test test = new Test(); + test.setId(id); + test.setTestId(testId); + test.setMarksAvailable(marksAvailable); + test.setTestResults(testResults); + return test; + } +} diff --git a/src/test/java/com/stileeducation/markr/util/TestResultBuilder.java b/src/test/java/com/stileeducation/markr/util/TestResultBuilder.java new file mode 100644 index 0000000..db26e15 --- /dev/null +++ b/src/test/java/com/stileeducation/markr/util/TestResultBuilder.java @@ -0,0 +1,36 @@ +package com.stileeducation.markr.util; + +import com.stileeducation.markr.entity.Student; +import com.stileeducation.markr.entity.Test; +import com.stileeducation.markr.entity.TestResult; + +public class TestResultBuilder { + private Long id; + private Student student; + private Test test; + private Integer marksAwarded; + + public TestResultBuilder withId(Long id) { + this.id = id; + return this; + } + + public TestResultBuilder withStudent(Student student) { + this.student = student; + return this; + } + + public TestResultBuilder withTest(Test test) { + this.test = test; + return this; + } + + public TestResultBuilder withMarksAwarded(Integer marksAwarded) { + this.marksAwarded = marksAwarded; + return this; + } + + public TestResult build() { + return new TestResult(id, student, test, marksAwarded); + } +}
\ No newline at end of file |
