Commit 6e72728e by Brian Wilson

Add more answer_dist coverage.

Also resolve remaining PEP8 warnings.

Change-Id: I1e5e1947ededbba97540e661c3fb6adcac100597
parent b82f7a8e
...@@ -277,8 +277,6 @@ class TestWeeklyIncrementalUsersAndEnrollments(unittest.TestCase): ...@@ -277,8 +277,6 @@ class TestWeeklyIncrementalUsersAndEnrollments(unittest.TestCase):
self.assertEqual(res.loc[self.row_label('enrollment_change')]['2013-01-15'], 2) self.assertEqual(res.loc[self.row_label('enrollment_change')]['2013-01-15'], 2)
class TestDailyRegistrationsEnrollmentsAndCourses(unittest.TestCase): class TestDailyRegistrationsEnrollmentsAndCourses(unittest.TestCase):
"""Tests for DailyRegistrationsEnrollmentsAndCourses class.""" """Tests for DailyRegistrationsEnrollmentsAndCourses class."""
......
...@@ -21,6 +21,7 @@ class LastProblemCheckEventBaseTest(unittest.TestCase): ...@@ -21,6 +21,7 @@ class LastProblemCheckEventBaseTest(unittest.TestCase):
self.org_id = self.course_id.split('/')[0] self.org_id = self.course_id.split('/')[0]
self.problem_id = "i4x://MITx/7.00x/2013_Spring/problem/PSet1:PS1_Q1" self.problem_id = "i4x://MITx/7.00x/2013_Spring/problem/PSet1:PS1_Q1"
self.answer_id = "i4x-MITx-7_00x-problem-PSet1_PS1_Q1_2_1" self.answer_id = "i4x-MITx-7_00x-problem-PSet1_PS1_Q1_2_1"
self.second_answer_id = "i4x-MITx-7_00x-problem-PSet1_PS1_Q1_3_1"
self.username = 'test_user' self.username = 'test_user'
self.user_id = 24 self.user_id = 24
self.timestamp = "2013-12-17T15:38:32.805444" self.timestamp = "2013-12-17T15:38:32.805444"
...@@ -31,6 +32,7 @@ class LastProblemCheckEventBaseTest(unittest.TestCase): ...@@ -31,6 +32,7 @@ class LastProblemCheckEventBaseTest(unittest.TestCase):
return json.dumps(self._create_event_dict(**kwargs)) return json.dumps(self._create_event_dict(**kwargs))
def _create_event_data_dict(self, **kwargs): def _create_event_data_dict(self, **kwargs):
"""Returns event data dict with test values."""
event_data = { event_data = {
"problem_id": self.problem_id, "problem_id": self.problem_id,
"seed": 1, "seed": 1,
...@@ -63,12 +65,13 @@ class LastProblemCheckEventBaseTest(unittest.TestCase): ...@@ -63,12 +65,13 @@ class LastProblemCheckEventBaseTest(unittest.TestCase):
@staticmethod @staticmethod
def _update_with_kwargs(data_dict, **kwargs): def _update_with_kwargs(data_dict, **kwargs):
# Update from kwargs only if it modifies a top-level value. """Updates a dict from kwargs only if it modifies a top-level value."""
for key, value in kwargs.iteritems(): for key, value in kwargs.iteritems():
if key in data_dict: if key in data_dict:
data_dict[key] = value data_dict[key] = value
def _create_event_context(self, **kwargs): def _create_event_context(self, **kwargs):
"""Returns context dict with test values."""
context = { context = {
"course_id": self.course_id, "course_id": self.course_id,
"org_id": self.org_id, "org_id": self.org_id,
...@@ -78,6 +81,7 @@ class LastProblemCheckEventBaseTest(unittest.TestCase): ...@@ -78,6 +81,7 @@ class LastProblemCheckEventBaseTest(unittest.TestCase):
return context return context
def _create_problem_data_dict(self, **kwargs): def _create_problem_data_dict(self, **kwargs):
"""Returns problem_data with test values."""
problem_data = self._create_event_data_dict(**kwargs) problem_data = self._create_event_data_dict(**kwargs)
problem_data['timestamp'] = self.timestamp problem_data['timestamp'] = self.timestamp
problem_data['username'] = self.username problem_data['username'] = self.username
...@@ -196,30 +200,30 @@ class LastProblemCheckEventReduceTest(LastProblemCheckEventBaseTest): ...@@ -196,30 +200,30 @@ class LastProblemCheckEventReduceTest(LastProblemCheckEventBaseTest):
return tuple(self.task.reducer(self.key, values)) return tuple(self.task.reducer(self.key, values))
def _check_output(self, inputs, expected): def _check_output(self, inputs, expected):
"""Compare generated with expected output.""" """
Compare generated with expected output.
Args:
inputs: array of values to pass to reducer
for hard-coded key.
expected: dict of expected answer data, with
answer_id as key.
"""
reducer_output = self._get_reducer_output(inputs) reducer_output = self._get_reducer_output(inputs)
self.assertEquals(len(reducer_output), len(expected)) self.assertEquals(len(reducer_output), len(expected))
for i, reducer_value in enumerate(reducer_output): for key, value in reducer_output:
expected_value = expected[i] course_id, answer_id = key
self.assertEquals(len(reducer_value), 2) timestamp, answer_data = value
self.assertEquals(reducer_value[0], expected_value[0]) self.assertEquals(course_id, self.course_id)
self.assertEquals(len(reducer_value[1]), 2) self.assertEquals(timestamp, self.timestamp)
self.assertEquals(reducer_value[1][0], self.timestamp) self.assertTrue(answer_id in expected)
# apparently the output of json.dumps() is not consistent enough self.assertEquals(json.loads(answer_data), expected.get(answer_id))
# to compare, due to ordering issues. So compare the dicts
# rather than the JSON strings.
actual_info = reducer_value[1][1]
actual_data = json.loads(actual_info)
expected_data = expected_value[1][1]
self.assertEquals(actual_data, expected_data)
def test_no_events(self): def test_no_events(self):
self._check_output([], tuple()) self._check_output([], tuple())
def test_one_answer_event(self): def _get_answer_data(self, **kwargs):
problem_data = self._create_problem_data_dict() """Returns expected answer data."""
input_data = (self.timestamp, json.dumps(problem_data))
answer_data = { answer_data = {
"answer_value_id": "3", "answer_value_id": "3",
"problem_display_name": None, "problem_display_name": None,
...@@ -227,10 +231,14 @@ class LastProblemCheckEventReduceTest(LastProblemCheckEventBaseTest): ...@@ -227,10 +231,14 @@ class LastProblemCheckEventReduceTest(LastProblemCheckEventBaseTest):
"correct": "incorrect", "correct": "incorrect",
"problem_id": self.problem_id, "problem_id": self.problem_id,
} }
expected_key = (self.course_id, self.answer_id) answer_data.update(**kwargs)
expected_value = (self.timestamp, answer_data) return answer_data
self._check_output([input_data], [(expected_key, expected_value)]) def test_one_answer_event(self):
problem_data = self._create_problem_data_dict()
input_data = (self.timestamp, json.dumps(problem_data))
answer_data = self._get_answer_data()
self._check_output([input_data], {self.answer_id: answer_data})
def test_one_submission_event(self): def test_one_submission_event(self):
problem_data = self._create_problem_data_dict() problem_data = self._create_problem_data_dict()
...@@ -245,27 +253,127 @@ class LastProblemCheckEventReduceTest(LastProblemCheckEventBaseTest): ...@@ -245,27 +253,127 @@ class LastProblemCheckEventReduceTest(LastProblemCheckEventBaseTest):
}, },
} }
input_data = (self.timestamp, json.dumps(problem_data)) input_data = (self.timestamp, json.dumps(problem_data))
answer_data = { answer_data = self._get_answer_data(
u"answer": u"3", answer="3",
u"problem_display_name": None, variant=629,
u"variant": 629, correct=False,
u"correct": False, input_type="formulaequationinput",
u"problem_id": unicode(self.problem_id), question="Enter the number of fingers on a human hand",
u"input_type": u"formulaequationinput", response_type="numericalresponse",
u"question": u"Enter the number of fingers on a human hand", )
u"response_type": u"numericalresponse", del answer_data['answer_value_id']
self._check_output([input_data], {self.answer_id: answer_data})
def test_one_submission_with_value_id(self):
problem_data = self._create_problem_data_dict()
problem_data['submission'] = {
self.answer_id: {
"input_type": "formulaequationinput",
"question": "Enter the number of fingers on a human hand",
"response_type": "choiceresponse",
"answer": "3",
"answer_value_id": "choice_3",
"variant": 629,
"correct": False
},
}
input_data = (self.timestamp, json.dumps(problem_data))
answer_data = self._get_answer_data(
answer="3",
answer_value_id="choice_3",
variant=629,
correct=False,
input_type="formulaequationinput",
question="Enter the number of fingers on a human hand",
response_type="choiceresponse",
)
self._check_output([input_data], {self.answer_id: answer_data})
def _add_second_answer(self, problem_data, answer_id=None):
"""Adds a second answer to an existing problem."""
if answer_id is None:
answer_id = self.second_answer_id
problem_data['answers'][answer_id] = "4"
problem_data['correct_map'][answer_id] = {
"correctness": "incorrect",
}
if 'submission' in problem_data:
problem_data['submission'][answer_id] = {
"input_type": "formulaequationinput",
"question": "Enter the number of fingers on the other hand",
"response_type": "numericalresponse",
"answer": "4",
"variant": 629,
"correct": False,
}
def test_two_answer_event(self):
problem_data = self._create_problem_data_dict()
self._add_second_answer(problem_data)
input_data = (self.timestamp, json.dumps(problem_data))
answer_data = self._get_answer_data()
answer_data_2 = self._get_answer_data(answer_value_id="4")
self._check_output([input_data], {
self.answer_id: answer_data, self.second_answer_id: answer_data_2
})
def test_two_answer_submission_event(self):
problem_data = self._create_problem_data_dict()
problem_data['submission'] = {
self.answer_id: {
"input_type": "formulaequationinput",
"question": "Enter the number of fingers on a human hand",
"response_type": "numericalresponse",
"answer": "3",
"variant": 1,
"correct": False
},
} }
expected_key = (self.course_id, self.answer_id) self._add_second_answer(problem_data)
expected_value = (self.timestamp, answer_data) input_data = (self.timestamp, json.dumps(problem_data))
self._check_output([input_data], [(expected_key, expected_value)]) answer_data = self._get_answer_data(
answer="3",
variant=1,
correct=False,
input_type="formulaequationinput",
question="Enter the number of fingers on a human hand",
response_type="numericalresponse",
)
del answer_data['answer_value_id']
answer_data_2 = self._get_answer_data(
answer="4",
variant=629,
correct=False,
input_type="formulaequationinput",
question="Enter the number of fingers on the other hand",
response_type="numericalresponse",
)
del answer_data_2['answer_value_id']
# TODO: test adding problem_display_name to context. self._check_output([input_data], {
# TODO: test with multiple answers from the same problem. self.answer_id: answer_data, self.second_answer_id: answer_data_2
# TODO: add hidden Ids })
# TODO: add submissions with answer_value_ids.
# TODO: test multiple answers from the same user (w/different times). def test_hidden_answer_event(self):
# (and different orders). for hidden_suffix in ['_dynamath', '_comment']:
problem_data = self._create_problem_data_dict()
hidden_answer_id = "{answer_id}{suffix}".format(
answer_id=self.answer_id, suffix=hidden_suffix
)
self._add_second_answer(problem_data, answer_id=hidden_answer_id)
input_data = (self.timestamp, json.dumps(problem_data))
answer_data = self._get_answer_data()
self._check_output([input_data], {self.answer_id: answer_data})
def test_problem_display_name(self):
problem_data = self._create_problem_data_dict()
problem_data['context']['module'] = {'display_name': "Display Name"}
input_data = (self.timestamp, json.dumps(problem_data))
answer_data = self._get_answer_data(problem_display_name="Display Name")
self._check_output([input_data], {self.answer_id: answer_data})
class AnswerDistributionPerCourseReduceTest(unittest.TestCase): class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
...@@ -299,6 +407,7 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -299,6 +407,7 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
self.assertEquals(reducer_outputs, expected_outputs) self.assertEquals(reducer_outputs, expected_outputs)
def _get_answer_data(self, **kwargs): def _get_answer_data(self, **kwargs):
"""Returns answer data for input with submission information."""
answer_data = { answer_data = {
"answer": "3", "answer": "3",
"problem_display_name": None, "problem_display_name": None,
...@@ -313,6 +422,7 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -313,6 +422,7 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
return answer_data return answer_data
def _get_non_submission_answer_data(self, **kwargs): def _get_non_submission_answer_data(self, **kwargs):
"""Returns answer data for input without submission information."""
answer_data = { answer_data = {
"answer_value_id": "3", "answer_value_id": "3",
"problem_display_name": None, "problem_display_name": None,
...@@ -366,20 +476,18 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -366,20 +476,18 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
answer='First Choice', answer='First Choice',
) )
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(answer_data, ValueID='choice_1', AnswerValue='First Choice')
ValueID='choice_1',
AnswerValue='First Choice'
)
self._check_output([input_data], (expected_output,)) self._check_output([input_data], (expected_output,))
def test_multiple_choice_answer(self): def test_multiple_choice_answer(self):
answer_data = self._get_answer_data( answer_data = self._get_answer_data(
answer_value_id=['choice_1','choice_2','choice_4'], answer_value_id=['choice_1', 'choice_2', 'choice_4'],
answer=['First Choice','Second Choice','Fourth Choice'], answer=['First Choice', 'Second Choice', 'Fourth Choice'],
response_type="multiplechoiceresponse", response_type="multiplechoiceresponse",
) )
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(
answer_data,
ValueID='[choice_1|choice_2|choice_4]', ValueID='[choice_1|choice_2|choice_4]',
AnswerValue='[First Choice|Second Choice|Fourth Choice]' AnswerValue='[First Choice|Second Choice|Fourth Choice]'
) )
...@@ -459,7 +567,8 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -459,7 +567,8 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
answer_value_id='choice_1', answer_value_id='choice_1',
) )
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(
answer_data,
ValueID='choice_1', ValueID='choice_1',
AnswerValue='First Choice', AnswerValue='First Choice',
Question="Pick One or Two", Question="Pick One or Two",
...@@ -472,10 +581,11 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -472,10 +581,11 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
answer_value_id_map={"choice_1": "First Choice", "choice_2": "Second Choice"} answer_value_id_map={"choice_1": "First Choice", "choice_2": "Second Choice"}
) )
answer_data = self._get_non_submission_answer_data( answer_data = self._get_non_submission_answer_data(
answer_value_id=['choice_1','choice_2'] answer_value_id=['choice_1', 'choice_2']
) )
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(
answer_data,
ValueID='[choice_1|choice_2]', ValueID='[choice_1|choice_2]',
AnswerValue='[First Choice|Second Choice]', AnswerValue='[First Choice|Second Choice]',
Question="Pick One or Two", Question="Pick One or Two",
...@@ -487,10 +597,11 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -487,10 +597,11 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
def test_non_submission_nonmapped_multichoice_with_metadata(self): def test_non_submission_nonmapped_multichoice_with_metadata(self):
self._load_metadata() self._load_metadata()
answer_data = self._get_non_submission_answer_data( answer_data = self._get_non_submission_answer_data(
answer_value_id=['choice_1','choice_2'] answer_value_id=['choice_1', 'choice_2']
) )
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(
answer_data,
ValueID='[choice_1|choice_2]', ValueID='[choice_1|choice_2]',
AnswerValue='', AnswerValue='',
Question="Pick One or Two", Question="Pick One or Two",
...@@ -504,7 +615,8 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -504,7 +615,8 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
answer_value_id='choice_1' answer_value_id='choice_1'
) )
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(
answer_data,
ValueID='choice_1', ValueID='choice_1',
AnswerValue='', AnswerValue='',
Question="Pick One or Two", Question="Pick One or Two",
...@@ -516,7 +628,8 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase): ...@@ -516,7 +628,8 @@ class AnswerDistributionPerCourseReduceTest(unittest.TestCase):
self._load_metadata(response_type="optionresponse") self._load_metadata(response_type="optionresponse")
answer_data = self._get_non_submission_answer_data() answer_data = self._get_non_submission_answer_data()
input_data = (self.timestamp, json.dumps(answer_data)) input_data = (self.timestamp, json.dumps(answer_data))
expected_output = self._get_expected_output(answer_data, expected_output = self._get_expected_output(
answer_data,
AnswerValue='3', AnswerValue='3',
Question="Pick One or Two", Question="Pick One or Two",
) )
......
Markdown is supported
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