Commit 86e24835 by Tim Krones

Update tests.

- Fix existing tests.
- Add unit tests for code that deals with instance-wide options.
- Add integration test for scenario where previous answers for MCQs are configured to be hidden.
parent 79bdff76
...@@ -131,6 +131,11 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest): ...@@ -131,6 +131,11 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
self.assertNotIn('checkmark-correct', choice_result_classes) self.assertNotIn('checkmark-correct', choice_result_classes)
self.assertNotIn('checkmark-incorrect', choice_result_classes) self.assertNotIn('checkmark-incorrect', choice_result_classes)
def _assert_not_checked(self, questionnaire, choice_index):
choice = self._get_choice(questionnaire, choice_index)
choice_input = choice.find_element_by_css_selector('input')
self.assertFalse(choice_input.is_selected())
def _standard_filling(self, answer, mcq, mrq, rating): def _standard_filling(self, answer, mcq, mrq, rating):
answer.send_keys('This is the answer') answer.send_keys('This is the answer')
self.click_choice(mcq, "Yes") self.click_choice(mcq, "Yes")
...@@ -164,6 +169,32 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest): ...@@ -164,6 +169,32 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
self.assertTrue(messages.is_displayed()) self.assertTrue(messages.is_displayed())
self.assertEqual(messages.text, "FEEDBACK\nNot done yet") self.assertEqual(messages.text, "FEEDBACK\nNot done yet")
def _feedback_customized_checks(self, answer, mcq, mrq, rating, messages):
# Long answer: Previous answer and feedback visible
self.assertEqual(answer.get_attribute('value'), 'This is the answer')
# MCQ: Previous answer and feedback hidden
for i in range(3):
self._assert_feedback_hidden(mcq, i)
self._assert_not_checked(mcq, i)
# MRQ: Previous answer and feedback visible
self._assert_feedback_showed(
mrq, 0, "This is something everyone has to like about this MRQ",
click_choice_result=True
)
self._assert_feedback_showed(
mrq, 1, "This is something everyone has to like about beauty",
click_choice_result=True, success=False
)
self._assert_feedback_showed(mrq, 2, "This MRQ is indeed very graceful", click_choice_result=True)
self._assert_feedback_showed(mrq, 3, "Nah, there aren't any!", click_choice_result=True, success=False)
# Rating: Previous answer and feedback hidden
for i in range(5):
self._assert_feedback_hidden(rating, i)
self._assert_not_checked(rating, i)
# Messages
self.assertTrue(messages.is_displayed())
self.assertEqual(messages.text, "FEEDBACK\nNot done yet")
def reload_student_view(self): def reload_student_view(self):
# Load another page (the home page), then go back to the page we want. This is the only reliable way to reload. # Load another page (the home page), then go back to the page we want. This is the only reliable way to reload.
self.browser.get(self.live_server_url + '/') self.browser.get(self.live_server_url + '/')
...@@ -218,6 +249,33 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest): ...@@ -218,6 +249,33 @@ class ProblemBuilderQuestionnaireBlockTest(ProblemBuilderBaseTest):
self.click_choice(mrq, "Its elegance") self.click_choice(mrq, "Its elegance")
self.assertTrue(submit.is_enabled()) self.assertTrue(submit.is_enabled())
def test_does_not_persist_mcq_feedback_on_page_reload_if_disabled(self):
with mock.patch("problem_builder.mentoring.MentoringBlock.get_options") as patched_options:
patched_options.return_value = {'pb_mcq_hide_previous_answer': True}
mentoring = self.load_scenario("feedback_persistence.xml")
answer, mcq, mrq, rating = self._get_controls(mentoring)
messages = self._get_messages_element(mentoring)
self._standard_filling(answer, mcq, mrq, rating)
self.click_submit(mentoring)
self._standard_checks(answer, mcq, mrq, rating, messages)
# now, reload the page and see if previous answers and results for MCQs are hidden
mentoring = self.reload_student_view()
answer, mcq, mrq, rating = self._get_controls(mentoring)
messages = self._get_messages_element(mentoring)
submit = mentoring.find_element_by_css_selector('.submit input.input-main')
self._feedback_customized_checks(answer, mcq, mrq, rating, messages)
# after reloading submit is disabled...
self.assertFalse(submit.is_enabled())
# ... until student answers MCQs again
self.click_choice(mcq, "Maybe not")
self.click_choice(rating, "2")
self.assertTrue(submit.is_enabled())
def test_given_perfect_score_in_past_loads_current_result(self): def test_given_perfect_score_in_past_loads_current_result(self):
mentoring = self.load_scenario("feedback_persistence.xml") mentoring = self.load_scenario("feedback_persistence.xml")
answer, mcq, mrq, rating = self._get_controls(mentoring) answer, mcq, mrq, rating = self._get_controls(mentoring)
......
...@@ -74,7 +74,7 @@ class StepTitlesTest(SeleniumXBlockTest): ...@@ -74,7 +74,7 @@ class StepTitlesTest(SeleniumXBlockTest):
mcq_template = """ mcq_template = """
<problem-builder mode="{{mode}}"> <problem-builder mode="{{mode}}">
<pb-mcq name="mcq_1_1" question="Who was your favorite character?" <pb-mcq name="mcq_1_1" question="Who was your favorite character?"
correct_choices="gaius,adama,starbuck,roslin,six,lee" correct_choices="[gaius,adama,starbuck,roslin,six,lee]"
{display_name_attr} {show_title_attr} {display_name_attr} {show_title_attr}
> >
<pb-choice value="gaius">Gaius Baltar</pb-choice> <pb-choice value="gaius">Gaius Baltar</pb-choice>
...@@ -90,7 +90,7 @@ class StepTitlesTest(SeleniumXBlockTest): ...@@ -90,7 +90,7 @@ class StepTitlesTest(SeleniumXBlockTest):
mrq_template = """ mrq_template = """
<problem-builder mode="{{mode}}"> <problem-builder mode="{{mode}}">
<pb-mrq name="mrq_1_1" question="What makes a great MRQ?" <pb-mrq name="mrq_1_1" question="What makes a great MRQ?"
ignored_choices="1,2,3" ignored_choices="[1,2,3]"
{display_name_attr} {show_title_attr} {display_name_attr} {show_title_attr}
> >
<pb-choice value="1">Lots of choices</pb-choice> <pb-choice value="1">Lots of choices</pb-choice>
...@@ -103,7 +103,7 @@ class StepTitlesTest(SeleniumXBlockTest): ...@@ -103,7 +103,7 @@ class StepTitlesTest(SeleniumXBlockTest):
rating_template = """ rating_template = """
<problem-builder mode="{{mode}}"> <problem-builder mode="{{mode}}">
<pb-rating name="rating_1_1" question="How do you rate Battlestar Galactica?" <pb-rating name="rating_1_1" question="How do you rate Battlestar Galactica?"
correct_choices="5,6" correct_choices="[5,6]"
{display_name_attr} {show_title_attr} {display_name_attr} {show_title_attr}
> >
<pb-choice value="6">More than 5 stars</pb-choice> <pb-choice value="6">More than 5 stars</pb-choice>
......
import unittest
import ddt import ddt
import unittest
from mock import MagicMock, Mock, patch from mock import MagicMock, Mock, patch
from random import random
from xblock.field_data import DictFieldData from xblock.field_data import DictFieldData
from problem_builder.mcq import MCQBlock from problem_builder.mcq import MCQBlock
from problem_builder.mentoring import MentoringBlock, MentoringMessageBlock, _default_theme_config from problem_builder.mentoring import (
MentoringBlock, MentoringMessageBlock, _default_theme_config, _default_options_config
)
@ddt.ddt @ddt.ddt
...@@ -64,45 +70,79 @@ class TestMentoringBlock(unittest.TestCase): ...@@ -64,45 +70,79 @@ class TestMentoringBlock(unittest.TestCase):
@ddt.ddt @ddt.ddt
class TestMentoringBlockTheming(unittest.TestCase): class TestMentoringBlockSettings(unittest.TestCase):
DEFAULT_SETTINGS = {
'get_theme': _default_theme_config,
'get_options': _default_options_config,
}
SETTINGS_KEYS = {
'get_theme': MentoringBlock.theme_key,
'get_options': MentoringBlock.options_key,
}
def setUp(self): def setUp(self):
self.service_mock = Mock() self.service_mock = Mock()
self.runtime_mock = Mock() self.runtime_mock = Mock()
self.runtime_mock.service = Mock(return_value=self.service_mock) self.runtime_mock.service = Mock(return_value=self.service_mock)
self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock()) self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())
def test_theme_uses_default_theme_if_settings_service_is_not_available(self): def test_settings_method_returns_default_if_settings_service_is_not_available(self):
for settings_method, default_config in self.DEFAULT_SETTINGS.items():
self.runtime_mock.service = Mock(return_value=None) self.runtime_mock.service = Mock(return_value=None)
self.assertEqual(self.block.get_theme(), _default_theme_config) self.assertEqual(getattr(self.block, settings_method)(), default_config)
def test_theme_uses_default_theme_if_no_theme_is_set(self): def test_settings_method_returns_default_if_settings_not_customized(self):
for settings_method, default_config in self.DEFAULT_SETTINGS.items():
self.service_mock.get_settings_bucket = Mock(return_value=None) self.service_mock.get_settings_bucket = Mock(return_value=None)
self.assertEqual(self.block.get_theme(), _default_theme_config) self.assertEqual(getattr(self.block, settings_method)(), default_config)
self.service_mock.get_settings_bucket.assert_called_once_with(self.block) self.service_mock.get_settings_bucket.assert_called_once_with(self.block)
@ddt.data(123, object()) @ddt.data(123, object())
def test_theme_raises_if_theme_object_is_not_iterable(self, theme_config): def test_settings_method_raises_if_settings_not_iterable(self, config):
self.service_mock.get_settings_bucket = Mock(return_value=theme_config) for settings_method in self.DEFAULT_SETTINGS:
self.service_mock.get_settings_bucket = Mock(return_value=config)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
self.block.get_theme() getattr(self.block, settings_method)()
self.service_mock.get_settings_bucket.assert_called_once_with(self.block) self.service_mock.get_settings_bucket.assert_called_once_with(self.block)
@ddt.data( @ddt.data(
{}, {'mass': 123}, {'spin': {}}, {'parity': "1"} {}, {'mass': 123}, {'spin': {}}, {'parity': "1"}
) )
def test_theme_uses_default_theme_if_no_mentoring_theme_is_set_up(self, theme_config): def test_settings_method_returns_default_if_target_setting_not_customized(self, config):
self.service_mock.get_settings_bucket = Mock(return_value=theme_config) for settings_method, default_config in self.DEFAULT_SETTINGS.items():
self.assertEqual(self.block.get_theme(), _default_theme_config) self.service_mock.get_settings_bucket = Mock(return_value=config)
self.assertEqual(getattr(self.block, settings_method)(), default_config)
self.service_mock.get_settings_bucket.assert_called_once_with(self.block) self.service_mock.get_settings_bucket.assert_called_once_with(self.block)
@ddt.data( @ddt.data(
{MentoringBlock.theme_key: 123}, {
{MentoringBlock.theme_key: [1, 2, 3]}, MentoringBlock.theme_key: 123,
{MentoringBlock.theme_key: {'package': 'qwerty', 'locations': ['something_else.css']}}, MentoringBlock.options_key: 123,
},
{
MentoringBlock.theme_key: [1, 2, 3],
MentoringBlock.options_key: [1, 2, 3],
},
{
MentoringBlock.theme_key: {'package': 'qwerty', 'locations': ['something_else.css']},
MentoringBlock.options_key: {'pb_mcq_hide_previous_answer': False},
},
) )
def test_theme_correctly_returns_configured_theme(self, theme_config): def test_settings_method_correctly_returns_customized_settings(self, config):
self.service_mock.get_settings_bucket = Mock(return_value=theme_config) for settings_method, settings_key in self.SETTINGS_KEYS.items():
self.assertEqual(self.block.get_theme(), theme_config[MentoringBlock.theme_key]) self.service_mock.get_settings_bucket = Mock(return_value=config)
self.assertEqual(getattr(self.block, settings_method)(), config[settings_key])
@ddt.ddt
class TestMentoringBlockTheming(unittest.TestCase):
def setUp(self):
self.service_mock = Mock()
self.runtime_mock = Mock()
self.runtime_mock.service = Mock(return_value=self.service_mock)
self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())
def test_theme_files_are_loaded_from_correct_package(self): def test_theme_files_are_loaded_from_correct_package(self):
fragment = MagicMock() fragment = MagicMock()
...@@ -131,16 +171,41 @@ class TestMentoringBlockTheming(unittest.TestCase): ...@@ -131,16 +171,41 @@ class TestMentoringBlockTheming(unittest.TestCase):
self.assertEqual(patched_load_unicode.call_count, len(locations)) self.assertEqual(patched_load_unicode.call_count, len(locations))
def test_student_view_calls_include_theme_files(self): def test_student_view_calls_include_theme_files(self):
self.service_mock.get_settings_bucket = Mock(return_value={})
with patch.object(self.block, 'include_theme_files') as patched_include_theme_files: with patch.object(self.block, 'include_theme_files') as patched_include_theme_files:
fragment = self.block.student_view({}) fragment = self.block.student_view({})
patched_include_theme_files.assert_called_with(fragment) patched_include_theme_files.assert_called_with(fragment)
def test_author_preview_view_calls_include_theme_files(self): def test_author_preview_view_calls_include_theme_files(self):
self.service_mock.get_settings_bucket = Mock(return_value={})
with patch.object(self.block, 'include_theme_files') as patched_include_theme_files: with patch.object(self.block, 'include_theme_files') as patched_include_theme_files:
fragment = self.block.author_preview_view({}) fragment = self.block.author_preview_view({})
patched_include_theme_files.assert_called_with(fragment) patched_include_theme_files.assert_called_with(fragment)
@ddt.ddt
class TestMentoringBlockOptions(unittest.TestCase):
def setUp(self):
self.service_mock = Mock()
self.runtime_mock = Mock()
self.runtime_mock.service = Mock(return_value=self.service_mock)
self.block = MentoringBlock(self.runtime_mock, DictFieldData({}), Mock())
def test_get_option(self):
random_key, random_value = random(), random()
with patch.object(self.block, 'get_options') as patched_get_options:
patched_get_options.return_value = {random_key: random_value}
option = self.block.get_option(random_key)
patched_get_options.assert_called_once_with()
self.assertEqual(option, random_value)
def test_student_view_calls_get_option(self):
self.service_mock.get_settings_bucket = Mock(return_value={})
with patch.object(self.block, 'get_option') as patched_get_option:
self.block.student_view({})
patched_get_option.assert_called_with('pb_mcq_hide_previous_answer')
class TestMentoringBlockJumpToIds(unittest.TestCase): class TestMentoringBlockJumpToIds(unittest.TestCase):
def setUp(self): def setUp(self):
self.service_mock = Mock() self.service_mock = Mock()
......
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