/* * This file is part of ARSnova Backend. * Copyright (C) 2012-2017 The ARSnova Team * * ARSnova Backend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ARSnova Backend is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.thm.arsnova.domain; import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.TestUser; import de.thm.arsnova.entities.User; import de.thm.arsnova.entities.transport.LearningProgressValues; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class QuestionBasedLearningProgressTest { private CourseScore courseScore; private VariantLearningProgress lp; private int id = 1; private String addQuestion(String questionVariant, int points) { final String questionId = "question" + (id++); final int piRound = 1; courseScore.addQuestion(questionId, questionVariant, piRound, points); return questionId; } private void addAnswer(String questionId, User user, int points) { final int piRound = 1; courseScore.addAnswer(questionId, piRound, user.getUsername(), points); } @Before public void setUp() { this.courseScore = new CourseScore(); IDatabaseDao db = mock(IDatabaseDao.class); when(db.getLearningProgress(null)).thenReturn(courseScore); this.lp = new QuestionBasedLearningProgress(db); } /** * Questions without "correct" answers should have a value of zero */ @Test public void shouldIgnoreQuestionsWithoutCorrectAnswers() { final int questionMaxValue = 0; final int userScore = 0; User user = new TestUser("username"); String questionId = this.addQuestion("lecture", questionMaxValue); this.addAnswer(questionId, user, userScore); LearningProgressValues expected = new LearningProgressValues(); expected.setCourseProgress(0); expected.setMyProgress(0); expected.setNumQuestions(0); LearningProgressValues actual = lp.getMyProgress(null, user); assertEquals(expected, actual); } @Test public void shouldIgnoreQuestionsWithoutCorrectAnswersInQuestionCount() { User user = new TestUser("username"); courseScore.addQuestion("question-without-correct-answers", "lecture", 1, 0); courseScore.addQuestion("question-with-correct-answers", "lecture", 1, 50); courseScore.addAnswer("question-without-correct-answers", 1, user.getUsername(), 0); courseScore.addAnswer("question-with-correct-answers", 1, user.getUsername(), 50); LearningProgressValues expected = new LearningProgressValues(); expected.setCourseProgress(100); expected.setMyProgress(100); expected.setNumQuestions(1); LearningProgressValues actual = lp.getMyProgress(null, user); assertEquals(expected, actual); } /** * If 99 users answer a question correctly, and 1 user does not, percentage should be 99%. */ @Test public void shouldCalculatePercentageOfOneQuestionWithSomeWrongAnswers() { String questionId = this.addQuestion("lecture", 10); for (int i = 0; i < 99; i++) { this.addAnswer(questionId, new TestUser("user"+i), 10); } this.addAnswer(questionId, new TestUser("user-with-a-wrong-answer"), 0); 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() { // two questions String q1 = this.addQuestion("lecture", 10); String q2 = this.addQuestion("lecture", 10); // two users User u1 = new TestUser("user1"); User u2 = new TestUser("user2"); // four answers, last one is wrong this.addAnswer(q1, u1, 10); this.addAnswer(q1, u2, 10); this.addAnswer(q2, u1, 10); this.addAnswer(q2, u2, 0); int expected = 75; int actual = lp.getCourseProgress(null).getCourseProgress(); assertEquals(expected, actual); } @Test public void shouldNotBeBiasedByPointsOrAnswerCount() { // two questions String q1 = this.addQuestion("lecture", 1000); String q2 = this.addQuestion("lecture", 1); // first question has many answers, all of them correct for (int i = 0; i < 100; i++) { this.addAnswer(q1, new TestUser("user"+i), 1000); } // second question has one wrong answer this.addAnswer(q2, new TestUser("another-user"), 0); int expected = 50; int actual = lp.getCourseProgress(null).getCourseProgress(); assertEquals(expected, actual); } @Test public void shouldFilterBasedOnQuestionVariant() { String q1 = this.addQuestion("lecture", 100); String q2 = this.addQuestion("preparation", 100); User u1 = new TestUser("user1"); User u2 = new TestUser("user2"); // first question is answered correctly, second one is not this.addAnswer(q1, u1, 100); this.addAnswer(q1, u2, 100); this.addAnswer(q2, u1, 0); this.addAnswer(q2, u2, 0); lp.setQuestionVariant("lecture"); LearningProgressValues lectureProgress = lp.getCourseProgress(null); LearningProgressValues myLectureProgress = lp.getMyProgress(null, u1); lp.setQuestionVariant("preparation"); LearningProgressValues prepProgress = lp.getCourseProgress(null); LearningProgressValues myPrepProgress = lp.getMyProgress(null, u1); assertEquals(100, lectureProgress.getCourseProgress()); assertEquals(100, myLectureProgress.getMyProgress()); assertEquals(0, prepProgress.getCourseProgress()); assertEquals(0, myPrepProgress.getMyProgress()); } @Test public void shouldConsiderAnswersOfSamePiRound() { User u1 = new TestUser("user1"); User u2 = new TestUser("user2"); // question is in round 2 courseScore.addQuestion("q1", "lecture", 2, 100); // 25 points in round 1, 75 points in round two for the first user courseScore.addAnswer("q1", 1, u1.getUsername(), 25); courseScore.addAnswer("q1", 2, u1.getUsername(), 100); // 75 points in round 1, 25 points in round two for the second user courseScore.addAnswer("q1", 1, u2.getUsername(), 100); courseScore.addAnswer("q1", 2, u2.getUsername(), 25); LearningProgressValues u1Progress = lp.getMyProgress(null, u1); LearningProgressValues u2Progress = lp.getMyProgress(null, u2); // only the answer for round 2 should be considered assertEquals(50, u1Progress.getCourseProgress()); assertEquals(100, u1Progress.getMyProgress()); assertEquals(50, u2Progress.getCourseProgress()); assertEquals(0, u2Progress.getMyProgress()); } @Test public void shouldIncludeNominatorAndDenominatorOfResultExcludingStudentCount() { // two questions String q1 = this.addQuestion("lecture", 10); String q2 = this.addQuestion("lecture", 10); // three users User u1 = new TestUser("user1"); User u2 = new TestUser("user2"); User u3 = new TestUser("user3"); // six answers this.addAnswer(q1, u1, 10); this.addAnswer(q2, u1, -100); this.addAnswer(q1, u2, -100); this.addAnswer(q2, u2, -100); this.addAnswer(q1, u3, -100); this.addAnswer(q2, u3, -100); int numerator = lp.getCourseProgress(null).getNumerator(); int denominator = lp.getCourseProgress(null).getDenominator(); // If the percentage is wrong, then we need to adapt this test case! assertEquals("Precondition failed -- The underlying calculation has changed", 17, lp.getCourseProgress(null).getCourseProgress()); assertEquals(0, numerator); assertEquals(2, denominator); } }