Commit 9e0ed9b7 by Awais Jibran

Merge pull request #8672 from edx/aj/tnl2551-randomized-problems-not-working

Fixed randomized problems which were not appearing to work.
parents 69b90275 e64ae13a
import logging import logging
import random import random
from lxml import etree
from xmodule.x_module import XModule, STUDENT_VIEW from xmodule.x_module import XModule, STUDENT_VIEW
from xmodule.seq_module import SequenceDescriptor from xmodule.seq_module import SequenceDescriptor
from lxml import etree
from xblock.fields import Scope, Integer from xblock.fields import Scope, Integer
from xblock.fragment import Fragment from xblock.fragment import Fragment
log = logging.getLogger('edx.' + __name__) log = logging.getLogger('edx.' + __name__)
...@@ -38,12 +37,11 @@ class RandomizeModule(RandomizeFields, XModule): ...@@ -38,12 +37,11 @@ class RandomizeModule(RandomizeFields, XModule):
grading interaction is a tangle between super and subclasses of descriptors and grading interaction is a tangle between super and subclasses of descriptors and
modules. modules.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(RandomizeModule, self).__init__(*args, **kwargs) super(RandomizeModule, self).__init__(*args, **kwargs)
# NOTE: calling self.get_children() creates a circular reference-- # NOTE: calling self.get_children() doesn't work until we've picked a choice
# it calls get_child_descriptors() internally, but that doesn't work until
# we've picked a choice
num_choices = len(self.descriptor.get_children()) num_choices = len(self.descriptor.get_children())
if self.choice > num_choices: if self.choice > num_choices:
...@@ -58,15 +56,23 @@ class RandomizeModule(RandomizeFields, XModule): ...@@ -58,15 +56,23 @@ class RandomizeModule(RandomizeFields, XModule):
else: else:
self.choice = random.randrange(0, num_choices) self.choice = random.randrange(0, num_choices)
if self.choice is not None: if self.child is not None:
self.child_descriptor = self.descriptor.get_children()[self.choice] log.debug("children of randomize module (should be only 1): %s", self.child)
# Now get_children() should return a list with one element
log.debug("children of randomize module (should be only 1): %s", @property
self.get_children()) def child_descriptor(self):
self.child = self.get_children()[0] """ Return descriptor of selected choice """
else: if self.choice is None:
self.child_descriptor = None return None
self.child = None return self.descriptor.get_children()[self.choice]
@property
def child(self):
""" Return module instance of selected choice """
child_descriptor = self.child_descriptor
if child_descriptor is None:
return None
return self.system.get_module(child_descriptor)
def get_child_descriptors(self): def get_child_descriptors(self):
""" """
...@@ -95,7 +101,6 @@ class RandomizeDescriptor(RandomizeFields, SequenceDescriptor): ...@@ -95,7 +101,6 @@ class RandomizeDescriptor(RandomizeFields, SequenceDescriptor):
filename_extension = "xml" filename_extension = "xml"
def definition_to_xml(self, resource_fs): def definition_to_xml(self, resource_fs):
xml_object = etree.Element('randomize') xml_object = etree.Element('randomize')
for child in self.get_children(): for child in self.get_children():
self.runtime.add_block_as_child_node(child, xml_object) self.runtime.add_block_as_child_node(child, xml_object)
......
import unittest import unittest
from datetime import datetime, timedelta
from django.utils.timezone import UTC
from opaque_keys.edx.locator import BlockUsageLocator
from xblock.fields import ScopeIds
from xmodule.randomize_module import RandomizeModule
from .test_course_module import DummySystem as DummyImportSystem from .test_course_module import DummySystem as DummyImportSystem
from xblock.field_data import DictFieldData
ORG = 'test_org' ORG = 'test_org'
COURSE = 'test_course' COURSE = 'test_course'
START = '2013-01-01T01:00:00' START = '2013-01-01T01:00:00'
_TODAY = datetime.now(UTC())
_LAST_WEEK = _TODAY - timedelta(days=7)
_NEXT_WEEK = _TODAY + timedelta(days=7)
class RandomizeModuleTestCase(unittest.TestCase): class RandomizeModuleTestCase(unittest.TestCase):
"""Make sure the randomize module works""" """Make sure the randomize module works"""
@staticmethod
def get_dummy_course(start):
"""Get a dummy course"""
system = DummyImportSystem(load_error_modules=True) def setUp(self):
"""
Initialize dummy testing course.
"""
super(RandomizeModuleTestCase, self).setUp()
self.system = DummyImportSystem(load_error_modules=True)
self.system.seed = None
self.course = self.get_dummy_course()
self.modulestore = self.system.modulestore
def to_attrb(n, v): def get_dummy_course(self, start=_TODAY):
return '' if v is None else '{0}="{1}"'.format(n, v).lower() """Get a dummy course"""
start_xml = ''' self.start_xml = '''
<course org="{org}" course="{course}" <course org="{org}" course="{course}"
graceperiod="1 day" url_name="test" graceperiod="1 day" url_name="test"
start="{start}" start="{start}">
> <chapter url="ch1" url_name="chapter1" display_name="CH1">
<chapter url="hi" url_name="ch" display_name="CH">
<randomize url_name="my_randomize"> <randomize url_name="my_randomize">
<html url_name="a" display_name="A">Two houses, ...</html> <html url_name="a" display_name="A">Two houses, ...</html>
<html url_name="b" display_name="B">Three houses, ...</html> <html url_name="b" display_name="B">Three houses, ...</html>
</randomize> </randomize>
</chapter> </chapter>
<chapter url="ch2" url_name="chapter2" display_name="CH2">
</chapter>
</course> </course>
'''.format(org=ORG, course=COURSE, start=start) '''.format(org=ORG, course=COURSE, start=start)
return system.process_xml(start_xml) return self.system.process_xml(self.start_xml)
def test_import(self): def test_import(self):
""" """
Just make sure descriptor loads without error Just make sure descriptor loads without error
""" """
descriptor = self.get_dummy_course(START) self.get_dummy_course(START)
def test_has_started(self):
"""
Test CourseDescriptor.has_started.
"""
self.course.start = _LAST_WEEK
self.assertTrue(self.course.has_started())
self.course.start = _NEXT_WEEK
self.assertFalse(self.course.has_started())
def test_children(self):
""" Check course/randomize module works fine """
self.assertTrue(self.course.has_children)
self.assertEquals(len(self.course.get_children()), 2)
def inner_get_module(descriptor):
"""
Override systems.get_module
This method will be called when any call is made to self.system.get_module
"""
if isinstance(descriptor, BlockUsageLocator):
location = descriptor
descriptor = self.modulestore.get_item(location, depth=None)
descriptor.xmodule_runtime = self.get_dummy_course()
descriptor.xmodule_runtime.descriptor_runtime = descriptor._runtime # pylint: disable=protected-access
descriptor.xmodule_runtime.get_module = inner_get_module
return descriptor
self.system.get_module = inner_get_module
# Get randomize_descriptor from the course & verify its children
randomize_descriptor = inner_get_module(self.course.id.make_usage_key('randomize', 'my_randomize'))
self.assertTrue(randomize_descriptor.has_children)
self.assertEquals(len(randomize_descriptor.get_children()), 2)
# TODO: add tests that create a module and check. Passing state is a good way to # Call RandomizeModule which will select an element from the list of available items
# check that child access works... randomize_module = RandomizeModule(
randomize_descriptor,
self.system,
DictFieldData({}),
ScopeIds(None, None, self.course.id, self.course.id)
)
self.assertTrue(randomize_module.child.display_name in ['A', 'B'])
self.assertTrue(randomize_module.get_children, 1)
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