Commit 85c31dd2 by Calen Pennington

Refactor test_xblock_wrappers to use Factories

parent 43215727
...@@ -7,6 +7,17 @@ functionality ...@@ -7,6 +7,17 @@ functionality
import webob import webob
import ddt import ddt
from factory import (
BUILD_STRATEGY,
Factory,
lazy_attribute,
LazyAttributeSequence,
post_generation,
SubFactory,
use_strategy,
)
from fs.memoryfs import MemoryFS
from lxml import etree
from mock import Mock from mock import Mock
from unittest.case import SkipTest, TestCase from unittest.case import SkipTest, TestCase
...@@ -15,7 +26,7 @@ from xblock.fields import ScopeIds ...@@ -15,7 +26,7 @@ from xblock.fields import ScopeIds
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.x_module import ModuleSystem, XModule, XModuleDescriptor from xmodule.x_module import ModuleSystem, XModule, XModuleDescriptor, DescriptorSystem
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
from xmodule.annotatable_module import AnnotatableDescriptor from xmodule.annotatable_module import AnnotatableDescriptor
from xmodule.capa_module import CapaDescriptor from xmodule.capa_module import CapaDescriptor
...@@ -37,30 +48,30 @@ from xmodule.vertical_module import VerticalDescriptor ...@@ -37,30 +48,30 @@ from xmodule.vertical_module import VerticalDescriptor
from xmodule.wrapper_module import WrapperDescriptor from xmodule.wrapper_module import WrapperDescriptor
from xmodule.tests import get_test_descriptor_system, get_test_system from xmodule.tests import get_test_descriptor_system, get_test_system
LEAF_XMODULES = ( LEAF_XMODULES = {
AnnotatableDescriptor, AnnotatableDescriptor: [{}],
CapaDescriptor, CapaDescriptor: [{}],
CombinedOpenEndedDescriptor, CombinedOpenEndedDescriptor: [{}],
DiscussionDescriptor, DiscussionDescriptor: [{}],
GraphicalSliderToolDescriptor, GraphicalSliderToolDescriptor: [{}],
HtmlDescriptor, HtmlDescriptor: [{}],
PeerGradingDescriptor, PeerGradingDescriptor: [{}],
PollDescriptor, PollDescriptor: [{'display_name': 'Poll Display Name'}],
WordCloudDescriptor, WordCloudDescriptor: [{}],
# This is being excluded because it has dependencies on django # This is being excluded because it has dependencies on django
#VideoDescriptor, #VideoDescriptor,
) }
CONTAINER_XMODULES = ( CONTAINER_XMODULES = {
ConditionalDescriptor, ConditionalDescriptor: [{}],
CourseDescriptor, CourseDescriptor: [{}],
CrowdsourceHinterDescriptor, CrowdsourceHinterDescriptor: [{}],
RandomizeDescriptor, RandomizeDescriptor: [{}],
SequenceDescriptor, SequenceDescriptor: [{}],
VerticalDescriptor, VerticalDescriptor: [{}],
WrapperDescriptor, WrapperDescriptor: [{}],
) }
# These modules are editable in studio yet # These modules are editable in studio yet
NOT_STUDIO_EDITABLE = ( NOT_STUDIO_EDITABLE = (
...@@ -70,60 +81,122 @@ NOT_STUDIO_EDITABLE = ( ...@@ -70,60 +81,122 @@ NOT_STUDIO_EDITABLE = (
) )
def leaf_module_runtime(): def flatten(class_dict):
return get_test_system() """
Flatten a dict from cls -> [fields, ...] to a list of the form [(cls, fields), ...]
"""
for cls, fields_list in class_dict.items():
for fields in fields_list:
yield (cls, fields)
@use_strategy(BUILD_STRATEGY)
class ModuleSystemFactory(Factory):
FACTORY_FOR = ModuleSystem
@classmethod
def _build(cls, target_class, *args, **kwargs):
return get_test_system(*args, **kwargs)
@use_strategy(BUILD_STRATEGY)
class DescriptorSystemFactory(Factory):
FACTORY_FOR = DescriptorSystem
@classmethod
def _build(cls, target_class, *args, **kwargs):
return get_test_descriptor_system(*args, **kwargs)
class LeafModuleRuntimeFactory(ModuleSystemFactory):
pass
def leaf_descriptor(descriptor_cls, idx=0):
location = Location('i4x://org/course/category/name')
runtime = get_test_descriptor_system()
return runtime.construct_xblock_from_class(
descriptor_cls,
ScopeIds(None, descriptor_cls.__name__, location, location),
DictFieldData({'url_name': '{}_{}'.format(descriptor_cls, idx)}),
)
class ContainerModuleRuntimeFactory(ModuleSystemFactory):
@post_generation
def depth(self, create, depth, **kwargs):
if depth == 0:
self.get_module.side_effect = lambda x: LeafModuleFactory(descriptor_cls=HtmlDescriptor)
else:
self.get_module.side_effect = lambda x: ContainerModuleFactory(descriptor_cls=VerticalDescriptor, depth=depth-1)
@post_generation
def position(self, create, position=2, **kwargs):
self.position = position
class ContainerDescriptorRuntimeFactory(DescriptorSystemFactory):
@post_generation
def depth(self, create, depth, **kwargs):
if depth == 0:
self.load_item.side_effect = lambda x: LeafModuleFactory(descriptor_cls=HtmlDescriptor)
else:
self.load_item.side_effect = lambda x: ContainerModuleFactory(descriptor_cls=VerticalDescriptor, depth=depth-1)
@post_generation
def position(self, create, position=2, **kwargs):
self.position = position
@use_strategy(BUILD_STRATEGY)
class LeafDescriptorFactory(Factory):
FACTORY_FOR = XModuleDescriptor
runtime = SubFactory(DescriptorSystemFactory)
url_name = LazyAttributeSequence('{.block_type}_{}'.format)
@lazy_attribute
def location(self):
return Location('i4x://org/course/category/{}'.format(self.url_name))
@lazy_attribute
def block_type(self):
return self.descriptor_cls.__name__
@lazy_attribute
def definition_id(self):
return self.location
@lazy_attribute
def usage_id(self):
return self.location
@classmethod
def _build(cls, target_class, *args, **kwargs):
runtime = kwargs.pop('runtime')
desc_cls = kwargs.pop('descriptor_cls')
block_type = kwargs.pop('block_type')
def_id = kwargs.pop('definition_id')
usage_id = kwargs.pop('usage_id')
block = runtime.construct_xblock_from_class(
desc_cls,
ScopeIds(None, block_type, def_id, usage_id),
DictFieldData(dict(**kwargs))
)
block.save()
return block
def leaf_module(descriptor_cls, idx=0):
"""Returns a descriptor that is ready to proxy as an xmodule"""
descriptor = leaf_descriptor(descriptor_cls, idx)
descriptor.xmodule_runtime = leaf_module_runtime()
return descriptor
class LeafModuleFactory(LeafDescriptorFactory):
def container_module_runtime(depth): @post_generation
runtime = leaf_module_runtime() def xmodule_runtime(self, create, xmodule_runtime, **kwargs):
if depth == 0: if xmodule_runtime is None:
runtime.get_module.side_effect = lambda x: leaf_module(HtmlDescriptor) xmodule_runtime = LeafModuleRuntimeFactory()
else:
runtime.get_module.side_effect = lambda x: container_module(VerticalDescriptor, depth - 1)
runtime.position = 2
return runtime
self.xmodule_runtime = xmodule_runtime
def container_descriptor(descriptor_cls, depth):
"""Return an instance of `descriptor_cls` with `depth` levels of children"""
location = Location('i4x://org/course/category/name')
runtime = get_test_descriptor_system()
if depth == 0: class ContainerDescriptorFactory(LeafDescriptorFactory):
runtime.load_item.side_effect = lambda x: leaf_module(HtmlDescriptor) runtime = SubFactory(ContainerDescriptorRuntimeFactory)
else: children = range(3)
runtime.load_item.side_effect = lambda x: container_module(VerticalDescriptor, depth - 1)
return runtime.construct_xblock_from_class(
descriptor_cls,
ScopeIds(None, descriptor_cls.__name__, location, location),
DictFieldData({
'children': range(3)
}),
)
def container_module(descriptor_cls, depth): class ContainerModuleFactory(LeafModuleFactory):
"""Returns a descriptor that is ready to proxy as an xmodule""" @lazy_attribute
descriptor = container_descriptor(descriptor_cls, depth) def xmodule_runtime(self):
descriptor.xmodule_runtime = container_module_runtime(depth) return ContainerModuleRuntimeFactory(depth=self.depth)
return descriptor
@ddt.ddt @ddt.ddt
...@@ -142,30 +215,32 @@ class TestXBlockWrapper(object): ...@@ -142,30 +215,32 @@ class TestXBlockWrapper(object):
# Test that for all of the leaf XModule Descriptors, # Test that for all of the leaf XModule Descriptors,
# the test property holds # the test property holds
@ddt.data(*LEAF_XMODULES) @ddt.data(*flatten(LEAF_XMODULES))
def test_leaf_node(self, descriptor_cls): def test_leaf_node(self, cls_and_fields):
descriptor_cls, fields = cls_and_fields
self.skip_if_invalid(descriptor_cls) self.skip_if_invalid(descriptor_cls)
descriptor = leaf_module(descriptor_cls) descriptor = LeafModuleFactory(descriptor_cls=descriptor_cls, **fields)
self.check_property(descriptor) self.check_property(descriptor)
# Test that when an xmodule is generated from descriptor_cls # Test that when an xmodule is generated from descriptor_cls
# with only xmodule children, the test property holds # with only xmodule children, the test property holds
@ddt.data(*CONTAINER_XMODULES) @ddt.data(*flatten(CONTAINER_XMODULES))
def test_container_node_xmodules_only(self, descriptor_cls): def test_container_node_xmodules_only(self, cls_and_fields):
descriptor_cls, fields = cls_and_fields
self.skip_if_invalid(descriptor_cls) self.skip_if_invalid(descriptor_cls)
descriptor = container_module(descriptor_cls, 2) descriptor = ContainerModuleFactory(descriptor_cls=descriptor_cls, depth=2, **fields)
self.check_property(descriptor) self.check_property(descriptor)
# Test that when an xmodule is generated from descriptor_cls # Test that when an xmodule is generated from descriptor_cls
# with mixed xmodule and xblock children, the test property holds # with mixed xmodule and xblock children, the test property holds
@ddt.data(*CONTAINER_XMODULES) @ddt.data(*flatten(CONTAINER_XMODULES))
def test_container_node_mixed(self, descriptor_cls): def test_container_node_mixed(self, cls_and_fields):
raise SkipTest("XBlock support in XDescriptor not yet fully implemented") raise SkipTest("XBlock support in XDescriptor not yet fully implemented")
# Test that when an xmodule is generated from descriptor_cls # Test that when an xmodule is generated from descriptor_cls
# with only xblock children, the test property holds # with only xblock children, the test property holds
@ddt.data(*CONTAINER_XMODULES) @ddt.data(*flatten(CONTAINER_XMODULES))
def test_container_node_xblocks_only(self, descriptor_cls): def test_container_node_xblocks_only(self, cls_and_fields):
raise SkipTest("XBlock support in XModules not yet fully implemented") raise SkipTest("XBlock support in XModules not yet fully implemented")
......
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