Skip to content
Snippets Groups Projects
Commit daee57b8 authored by Christoph Thelen's avatar Christoph Thelen
Browse files

Fix for #14841: Properly weight wrong answers

Previously, a single wrong answer was sufficient for a
question to get a 0% score. With this change, they
are counted as much as a correct answer. The only
difference now is that they reduce the overall
score of a question. See test cases for a
few examples.
parent 8dbd71f0
Branches
Tags
No related merge requests found
...@@ -41,32 +41,29 @@ public class QuestionBasedLearningProgress implements LearningProgress { ...@@ -41,32 +41,29 @@ public class QuestionBasedLearningProgress implements LearningProgress {
} }
private int calculateCourseProgress(CourseScore courseScore) { private int calculateCourseProgress(CourseScore courseScore) {
int numQuestionsCorrect = numQuestionsCorrectForCourse(courseScore);
final double correctQuestionsOnAverage = (double)numQuestionsCorrect / (double)(courseScore.getQuestionCount());
// calculate percent, cap results to 100 // calculate percent, cap results to 100
return (int) Math.min(100, Math.round(correctQuestionsOnAverage*100)); return (int) Math.min(100, Math.round(correctAnswerRatio(courseScore)*100));
} }
private int numQuestionsCorrectForCourse(CourseScore courseScore) { private double correctAnswerRatio(CourseScore courseScore) {
// a question is seen as "correct" if and only if all participants have answered it correctly double ratio = 0;
int numQuestionsCorrect = 0;
for (QuestionScore questionScore : courseScore) { for (QuestionScore questionScore : courseScore) {
int numAnswers = questionScore.getUserCount();
int numAnswersCorrect = 0;
int requiredScore = questionScore.getMaximum(); int requiredScore = questionScore.getMaximum();
if (!questionScore.hasScores()) { if (!questionScore.hasScores()) {
continue; continue;
} }
boolean allCorrect = true;
for (UserScore userScore : questionScore) { for (UserScore userScore : questionScore) {
if (!userScore.hasScore(requiredScore)) { if (userScore.hasScore(requiredScore)) {
allCorrect = false; numAnswersCorrect++;
break;
} }
} }
if (allCorrect) { if (numAnswers != 0) {
numQuestionsCorrect++; ratio += (double)numAnswersCorrect / (numAnswers * courseScore.getQuestionCount());
} }
} }
return numQuestionsCorrect; return ratio;
} }
@Override @Override
......
...@@ -76,4 +76,79 @@ public class QuestionBasedLearningProgressTest { ...@@ -76,4 +76,79 @@ public class QuestionBasedLearningProgressTest {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
/**
* If 99 users answer a question correctly, and 1 user does not, percentage should be 99%.
*/
@Test
public void shouldCalculatePercentageOfOneQuestionWithSomeWrongAnswers() {
CourseScore courseScore = new CourseScore();
courseScore.add("question", 10);
for (int i = 0; i < 99; i++) {
courseScore.add("question", new TestUser("user"+i).getUsername(), 10);
}
courseScore.add("question", new TestUser("user-with-a-wrong-answer").getUsername(), 0);
IDatabaseDao db = mock(IDatabaseDao.class);
when(db.getLearningProgress(null)).thenReturn(courseScore);
LearningProgress lp = new QuestionBasedLearningProgress(db);
int expected = 99;
int actual = lp.getCourseProgress(null).getCourseProgress();
assertEquals(expected, actual);
}
/**
* Given two users and two questions: the first question is answered correctly by both users, while the second
* is only answered correctly by one user. The first question should receive 100%, the second 50%. This should
* result in an overall score of 75%.
*/
@Test
public void shouldCalculatePercentageOfMultipleQuestionsAndAnswers() {
CourseScore courseScore = new CourseScore();
// two questions
courseScore.add("question1", 10);
courseScore.add("question2", 10);
// two users
User u1 = new TestUser("user1");
User u2 = new TestUser("user2");
// four answers, last one is wrong
courseScore.add("question1", u1.getUsername(), 10);
courseScore.add("question1", u2.getUsername(), 10);
courseScore.add("question2", u1.getUsername(), 10);
courseScore.add("question2", u2.getUsername(), 0);
IDatabaseDao db = mock(IDatabaseDao.class);
when(db.getLearningProgress(null)).thenReturn(courseScore);
LearningProgress lp = new QuestionBasedLearningProgress(db);
int expected = 75;
int actual = lp.getCourseProgress(null).getCourseProgress();
assertEquals(expected, actual);
}
@Test
public void shouldNotBeBiasedByPointsOrAnswerCount() {
CourseScore courseScore = new CourseScore();
// two questions
courseScore.add("question1", 1000);
courseScore.add("question2", 1);
// first question has many answers, all of them correct
for (int i = 0; i < 100; i++) {
courseScore.add("question1", new TestUser("user"+i).getUsername(), 1000);
}
// second question has one wrong answer
courseScore.add("question2", new TestUser("another-user").getUsername(), 0);
IDatabaseDao db = mock(IDatabaseDao.class);
when(db.getLearningProgress(null)).thenReturn(courseScore);
LearningProgress lp = new QuestionBasedLearningProgress(db);
int expected = 50;
int actual = lp.getCourseProgress(null).getCourseProgress();
assertEquals(expected, actual);
}
} }
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