diff --git a/cms/djangoapps/contentstore/tests/factories.py b/cms/djangoapps/contentstore/tests/factories.py deleted file mode 100644 index d15610f11c..0000000000 --- a/cms/djangoapps/contentstore/tests/factories.py +++ /dev/null @@ -1,49 +0,0 @@ -from factory import Factory -from datetime import datetime -from uuid import uuid4 -from student.models import (User, UserProfile, Registration, - CourseEnrollmentAllowed) -from django.contrib.auth.models import Group - - -class UserProfileFactory(Factory): - FACTORY_FOR = UserProfile - - user = None - name = 'Robot Studio' - courseware = 'course.xml' - - -class RegistrationFactory(Factory): - FACTORY_FOR = Registration - - user = None - activation_key = uuid4().hex - - -class UserFactory(Factory): - FACTORY_FOR = User - - username = 'robot' - email = 'robot@edx.org' - password = 'test' - first_name = 'Robot' - last_name = 'Tester' - is_staff = False - is_active = True - is_superuser = False - last_login = datetime.now() - date_joined = datetime.now() - - -class GroupFactory(Factory): - FACTORY_FOR = Group - - name = 'test_group' - - -class CourseEnrollmentAllowedFactory(Factory): - FACTORY_FOR = CourseEnrollmentAllowed - - email = 'test@edx.org' - course_id = 'edX/test/2012_Fall' diff --git a/cms/envs/test.py b/cms/envs/test.py index 7f39e6818b..abe03edd41 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -27,6 +27,9 @@ STATIC_ROOT = TEST_ROOT / "staticfiles" GITHUB_REPO_ROOT = TEST_ROOT / "data" COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data" +# Makes the tests run much faster... +SOUTH_TESTS_MIGRATE = False # To disable migrations and use syncdb instead + # TODO (cpennington): We need to figure out how envs/test.py can inject things into common.py so that we don't have to repeat this sort of thing STATICFILES_DIRS = [ COMMON_ROOT / "static", diff --git a/lms/djangoapps/courseware/tests/test_access.py b/lms/djangoapps/courseware/tests/test_access.py index c0b28e7803..acb05d5d78 100644 --- a/lms/djangoapps/courseware/tests/test_access.py +++ b/lms/djangoapps/courseware/tests/test_access.py @@ -1,11 +1,18 @@ import unittest +import logging import time -from mock import Mock +from mock import Mock, MagicMock, patch + +from django.conf import settings from django.test import TestCase +from xmodule.course_module import CourseDescriptor +from xmodule.error_module import ErrorDescriptor from xmodule.modulestore import Location -from factories import CourseEnrollmentAllowedFactory +from xmodule.timeparse import parse_time +from xmodule.x_module import XModule, XModuleDescriptor import courseware.access as access +from factories import CourseEnrollmentAllowedFactory class AccessTestCase(TestCase): diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py new file mode 100644 index 0000000000..81f95a85e4 --- /dev/null +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -0,0 +1,178 @@ +import logging +from mock import MagicMock, patch +import json +import factory +import unittest +from nose.tools import set_trace + +from django.http import Http404, HttpResponse, HttpRequest +from django.conf import settings +from django.contrib.auth.models import User +from django.test.client import Client +from django.conf import settings +from django.test import TestCase +from django.test.client import RequestFactory +from django.core.urlresolvers import reverse +from django.test.utils import override_settings + +from courseware.models import StudentModule, StudentModuleCache +from xmodule.modulestore.exceptions import ItemNotFoundError +from xmodule.exceptions import NotFoundError +from xmodule.modulestore import Location +import courseware.module_render as render +from xmodule.modulestore.django import modulestore, _MODULESTORES +from xmodule.seq_module import SequenceModule +from courseware.tests.tests import PageLoader +from student.models import Registration + +from factories import UserFactory + + +class Stub: + def __init__(self): + pass + + +def xml_store_config(data_dir): + return { + 'default': { + 'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore', + 'OPTIONS': { + 'data_dir': data_dir, + 'default_class': 'xmodule.hidden_module.HiddenDescriptor', + } + } + } + +TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT +TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR) + + +@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +class ModuleRenderTestCase(PageLoader): + def setUp(self): + self.location = ['i4x', 'edX', 'toy', 'chapter', 'Overview'] + self._MODULESTORES = {} + self.course_id = 'edX/toy/2012_Fall' + self.toy_course = modulestore().get_course(self.course_id) + + def test_get_module(self): + self.assertIsNone(render.get_module('dummyuser', None, + 'invalid location', None, None)) + + def test_get_instance_module(self): + mock_user = MagicMock() + mock_user.is_authenticated.return_value = False + self.assertIsNone(render.get_instance_module('dummy', mock_user, 'dummy', + 'dummy')) + mock_user_2 = MagicMock() + mock_user_2.is_authenticated.return_value = True + mock_module = MagicMock() + mock_module.descriptor.stores_state = False + self.assertIsNone(render.get_instance_module('dummy', mock_user_2, + mock_module, 'dummy')) + + def test_modx_dispatch(self): + self.assertRaises(Http404, render.modx_dispatch, 'dummy', 'dummy', + 'invalid Location', 'dummy') + mock_request = MagicMock() + mock_request.FILES.keys.return_value = ['file_id'] + mock_request.FILES.getlist.return_value = ['file'] * (settings.MAX_FILEUPLOADS_PER_INPUT + 1) + self.assertEquals(render.modx_dispatch(mock_request, 'dummy', self.location, + 'dummy').content, + json.dumps({'success': 'Submission aborted! Maximum %d files may be submitted at once' % + settings.MAX_FILEUPLOADS_PER_INPUT})) + mock_request_2 = MagicMock() + mock_request_2.FILES.keys.return_value = ['file_id'] + inputfile = Stub() + inputfile.size = 1 + settings.STUDENT_FILEUPLOAD_MAX_SIZE + inputfile.name = 'name' + filelist = [inputfile] + mock_request_2.FILES.getlist.return_value = filelist + self.assertEquals(render.modx_dispatch(mock_request_2, 'dummy', self.location, + 'dummy').content, + json.dumps({'success': 'Submission aborted! Your file "%s" is too large (max size: %d MB)' % + (inputfile.name, settings.STUDENT_FILEUPLOAD_MAX_SIZE / (1000 ** 2))})) + mock_request_3 = MagicMock() + mock_request_3.POST.copy.return_value = {} + mock_request_3.FILES = False + mock_request_3.user = UserFactory() + inputfile_2 = Stub() + inputfile_2.size = 1 + inputfile_2.name = 'name' + self.assertRaises(ItemNotFoundError, render.modx_dispatch, + mock_request_3, 'dummy', self.location, 'toy') + self.assertRaises(Http404, render.modx_dispatch, mock_request_3, 'dummy', + self.location, self.course_id) + mock_request_3.POST.copy.return_value = {'position': 1} + self.assertIsInstance(render.modx_dispatch(mock_request_3, 'goto_position', + self.location, self.course_id), HttpResponse) + + def test_get_score_bucket(self): + self.assertEquals(render.get_score_bucket(0, 10), 'incorrect') + self.assertEquals(render.get_score_bucket(1, 10), 'partial') + self.assertEquals(render.get_score_bucket(10, 10), 'correct') + # get_score_bucket calls error cases 'incorrect' + self.assertEquals(render.get_score_bucket(11, 10), 'incorrect') + self.assertEquals(render.get_score_bucket(-1, 10), 'incorrect') + + +@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +class TestTOC(TestCase): + """Check the Table of Contents for a course""" + def setUp(self): + self._MODULESTORES = {} + + # Toy courses should be loaded + self.course_name = 'edX/toy/2012_Fall' + self.toy_course = modulestore().get_course(self.course_name) + self.portal_user = UserFactory() + + def test_toc_toy_from_chapter(self): + chapter = 'Overview' + chapter_url = '%s/%s/%s' % ('/courses', self.course_name, chapter) + factory = RequestFactory() + request = factory.get(chapter_url) + + expected = ([{'active': True, 'sections': + [{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, + 'format': u'Lecture Sequence', 'due': '', 'active': False}, + {'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, + 'format': '', 'due': '', 'active': False}, + {'url_name': 'video_123456789012', 'display_name': 'video 123456789012', 'graded': True, + 'format': '', 'due': '', 'active': False}, + {'url_name': 'video_4f66f493ac8f', 'display_name': 'video 4f66f493ac8f', 'graded': True, + 'format': '', 'due': '', 'active': False}], + 'url_name': 'Overview', 'display_name': u'Overview'}, + {'active': False, 'sections': + [{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, + 'format': '', 'due': '', 'active': False}], + 'url_name': 'secret:magic', 'display_name': 'secret:magic'}]) + + actual = render.toc_for_course(self.portal_user, request, self.toy_course, chapter, None) + self.assertEqual(expected, actual) + + def test_toc_toy_from_section(self): + chapter = 'Overview' + chapter_url = '%s/%s/%s' % ('/courses', self.course_name, chapter) + section = 'Welcome' + factory = RequestFactory() + request = factory.get(chapter_url) + + expected = ([{'active': True, 'sections': + [{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, + 'format': u'Lecture Sequence', 'due': '', 'active': False}, + {'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, + 'format': '', 'due': '', 'active': True}, + {'url_name': 'video_123456789012', 'display_name': 'video 123456789012', 'graded': True, + 'format': '', 'due': '', 'active': False}, + {'url_name': 'video_4f66f493ac8f', 'display_name': 'video 4f66f493ac8f', 'graded': True, + 'format': '', 'due': '', 'active': False}], + 'url_name': 'Overview', 'display_name': u'Overview'}, + {'active': False, 'sections': + [{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, + 'format': '', 'due': '', 'active': False}], + 'url_name': 'secret:magic', 'display_name': 'secret:magic'}]) + + actual = render.toc_for_course(self.portal_user, request, self.toy_course, chapter, section) + self.assertEqual(expected, actual) diff --git a/lms/djangoapps/courseware/tests/test_progress.py b/lms/djangoapps/courseware/tests/test_progress.py new file mode 100644 index 0000000000..a70cbe4b9a --- /dev/null +++ b/lms/djangoapps/courseware/tests/test_progress.py @@ -0,0 +1,57 @@ +from django.test import TestCase +from courseware import progress +from mock import MagicMock + + +class ProgessTests(TestCase): + def setUp(self): + + self.d = dict({'duration_total': 0, + 'duration_watched': 0, + 'done': True, + 'questions_correct': 4, + 'questions_incorrect': 0, + 'questions_total': 0}) + + self.c = progress.completion() + self.c2 = progress.completion() + self.c2.dict = dict({'duration_total': 0, + 'duration_watched': 0, + 'done': True, + 'questions_correct': 2, + 'questions_incorrect': 1, + 'questions_total': 0}) + + self.cplusc2 = dict({'duration_total': 0, + 'duration_watched': 0, + 'done': True, + 'questions_correct': 2, + 'questions_incorrect': 1, + 'questions_total': 0}) + + self.oth = dict({'duration_total': 0, + 'duration_watched': 0, + 'done': True, + 'questions_correct': 4, + 'questions_incorrect': 0, + 'questions_total': 7}) + + self.x = MagicMock() + self.x.dict = self.oth + + self.d_oth = {'duration_total': 0, + 'duration_watched': 0, + 'done': True, + 'questions_correct': 4, + 'questions_incorrect': 0, + 'questions_total': 7} + + def test_getitem(self): + self.assertEqual(self.c.__getitem__('duration_watched'), 0) + + def test_setitem(self): + self.c.__setitem__('questions_correct', 4) + self.assertEqual(str(self.c), str(self.d)) + + def test_repr(self): + self.assertEqual(self.c.__repr__(), str(progress.completion())) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py new file mode 100644 index 0000000000..eeac999813 --- /dev/null +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -0,0 +1,126 @@ +import logging +from mock import MagicMock, patch +import datetime +import factory +import unittest +import os + +from django.test import TestCase +from django.http import Http404, HttpResponse +from django.conf import settings +from django.test.utils import override_settings +from django.contrib.auth.models import User +from django.test.client import RequestFactory + +from student.models import CourseEnrollment +from xmodule.modulestore.django import modulestore, _MODULESTORES +from xmodule.modulestore.exceptions import InvalidLocationError,\ + ItemNotFoundError, NoPathToItem +import courseware.views as views +from xmodule.modulestore import Location + +from factories import UserFactory + + +class Stub(): + pass + + +# This part is required for modulestore() to work properly +def xml_store_config(data_dir): + return { + 'default': { + 'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore', + 'OPTIONS': { + 'data_dir': data_dir, + 'default_class': 'xmodule.hidden_module.HiddenDescriptor', + } + } + } + +TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT +TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR) + + +@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +class TestJumpTo(TestCase): + """Check the jumpto link for a course""" + def setUp(self): + self._MODULESTORES = {} + + # Toy courses should be loaded + self.course_name = 'edX/toy/2012_Fall' + self.toy_course = modulestore().get_course('edX/toy/2012_Fall') + + def test_jumpto_invalid_location(self): + location = Location('i4x', 'edX', 'toy', 'NoSuchPlace', None) + jumpto_url = '%s/%s/jump_to/%s' % ('/courses', self.course_name, location) + expected = 'courses/edX/toy/2012_Fall/courseware/Overview/' + response = self.client.get(jumpto_url) + self.assertEqual(response.status_code, 404) + + def test_jumpto_from_chapter(self): + location = Location('i4x', 'edX', 'toy', 'chapter', 'Overview') + jumpto_url = '%s/%s/jump_to/%s' % ('/courses', self.course_name, location) + expected = 'courses/edX/toy/2012_Fall/courseware/Overview/' + response = self.client.get(jumpto_url) + self.assertRedirects(response, expected, status_code=302, target_status_code=302) + + +class ViewsTestCase(TestCase): + def setUp(self): + self.user = User.objects.create(username='dummy', password='123456', + email='test@mit.edu') + self.date = datetime.datetime(2013, 1, 22) + self.course_id = 'edX/toy/2012_Fall' + self.enrollment = CourseEnrollment.objects.get_or_create(user=self.user, + course_id=self.course_id, + created=self.date)[0] + self.location = ['tag', 'org', 'course', 'category', 'name'] + self._MODULESTORES = {} + # This is a CourseDescriptor object + self.toy_course = modulestore().get_course('edX/toy/2012_Fall') + self.request_factory = RequestFactory() + chapter = 'Overview' + self.chapter_url = '%s/%s/%s' % ('/courses', self.course_id, chapter) + + def test_user_groups(self): + # depreciated function + mock_user = MagicMock() + mock_user.is_authenticated.return_value = False + self.assertEquals(views.user_groups(mock_user), []) + + def test_get_current_child(self): + self.assertIsNone(views.get_current_child(Stub())) + mock_xmodule = MagicMock() + mock_xmodule.position = -1 + mock_xmodule.get_display_items.return_value = ['one', 'two'] + self.assertEquals(views.get_current_child(mock_xmodule), 'one') + mock_xmodule_2 = MagicMock() + mock_xmodule_2.position = 3 + mock_xmodule_2.get_display_items.return_value = [] + self.assertIsNone(views.get_current_child(mock_xmodule_2)) + + def test_redirect_to_course_position(self): + mock_module = MagicMock() + mock_module.descriptor.id = 'Underwater Basketweaving' + mock_module.position = 3 + mock_module.get_display_items.return_value = [] + self.assertRaises(Http404, views.redirect_to_course_position, + mock_module, True) + + def test_registered_for_course(self): + self.assertFalse(views.registered_for_course('Basketweaving', None)) + mock_user = MagicMock() + mock_user.is_authenticated.return_value = False + self.assertFalse(views.registered_for_course('dummy', mock_user)) + mock_course = MagicMock() + mock_course.id = self.course_id + self.assertTrue(views.registered_for_course(mock_course, self.user)) + + def test_jump_to_invalid(self): + request = self.request_factory.get(self.chapter_url) + self.assertRaisesRegexp(Http404, 'Invalid location', views.jump_to, + request, 'bar', ()) + self.assertRaisesRegexp(Http404, 'No data*', views.jump_to, request, + 'dummy', self.location) diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py index fb6842d4a9..7e00baf61f 100644 --- a/lms/djangoapps/courseware/tests/tests.py +++ b/lms/djangoapps/courseware/tests/tests.py @@ -53,46 +53,46 @@ def registration(email): def mongo_store_config(data_dir): return { - 'default': { - 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', - 'OPTIONS': { - 'default_class': 'xmodule.raw_module.RawDescriptor', - 'host': 'localhost', - 'db': 'test_xmodule', - 'collection': 'modulestore', - 'fs_root': data_dir, - 'render_template': 'mitxmako.shortcuts.render_to_string', + 'default': { + 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', + 'OPTIONS': { + 'default_class': 'xmodule.raw_module.RawDescriptor', + 'host': 'localhost', + 'db': 'test_xmodule', + 'collection': 'modulestore', + 'fs_root': data_dir, + 'render_template': 'mitxmako.shortcuts.render_to_string', + } } } -} def draft_mongo_store_config(data_dir): return { - 'default': { - 'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore', - 'OPTIONS': { - 'default_class': 'xmodule.raw_module.RawDescriptor', - 'host': 'localhost', - 'db': 'test_xmodule', - 'collection': 'modulestore', - 'fs_root': data_dir, - 'render_template': 'mitxmako.shortcuts.render_to_string', + 'default': { + 'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore', + 'OPTIONS': { + 'default_class': 'xmodule.raw_module.RawDescriptor', + 'host': 'localhost', + 'db': 'test_xmodule', + 'collection': 'modulestore', + 'fs_root': data_dir, + 'render_template': 'mitxmako.shortcuts.render_to_string', + } } } -} def xml_store_config(data_dir): return { - 'default': { - 'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore', - 'OPTIONS': { - 'data_dir': data_dir, - 'default_class': 'xmodule.hidden_module.HiddenDescriptor', + 'default': { + 'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore', + 'OPTIONS': { + 'data_dir': data_dir, + 'default_class': 'xmodule.hidden_module.HiddenDescriptor', + } } } -} TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR) @@ -115,8 +115,7 @@ class ActivateLoginTestCase(TestCase): 'Response status code was {0} instead of 302'.format(response.status_code)) url = response['Location'] - e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit( - expected_url) + e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url) if not (e_scheme or e_netloc): expected_url = urlunsplit(('http', 'testserver', e_path, e_query, e_fragment)) @@ -211,7 +210,7 @@ class PageLoader(ActivateLoginTestCase): resp = self.client.post('/change_enrollment', { 'enrollment_action': 'enroll', 'course_id': course.id, - }) + }) return parse_json(resp) def try_enroll(self, course): @@ -230,11 +229,10 @@ class PageLoader(ActivateLoginTestCase): resp = self.client.post('/change_enrollment', { 'enrollment_action': 'unenroll', 'course_id': course.id, - }) + }) data = parse_json(resp) self.assertTrue(data['success']) - def check_for_get_code(self, code, url): """ Check that we got the expected code when accessing url via GET. @@ -246,7 +244,6 @@ class PageLoader(ActivateLoginTestCase): .format(resp.status_code, url, code)) return resp - def check_for_post_code(self, code, url, data={}): """ Check that we got the expected code when accessing url via POST. @@ -258,12 +255,8 @@ class PageLoader(ActivateLoginTestCase): .format(resp.status_code, url, code)) return resp - - def check_pages_load(self, module_store): """Make all locations in course load""" - - # enroll in the course before trying to access pages courses = module_store.get_courses() self.assertEqual(len(courses), 1) @@ -316,7 +309,7 @@ class PageLoader(ActivateLoginTestCase): msg = str(resp.status_code) if resp.status_code != 200: - msg = "ERROR " + msg + ": " + descriptor.location.url() + msg = "ERROR " + msg + ": " + descriptor.location.url() all_ok = False num_bad += 1 elif resp.redirect_chain[0][1] != 302: @@ -344,7 +337,6 @@ class PageLoader(ActivateLoginTestCase): self.assertTrue(all_ok) - @override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) class TestCoursesLoadTestCase_XmlModulestore(PageLoader): '''Check that all pages in test courses load properly''' @@ -355,21 +347,21 @@ class TestCoursesLoadTestCase_XmlModulestore(PageLoader): def test_toy_course_loads(self): module_store = XMLModuleStore( - TEST_DATA_DIR, - default_class='xmodule.hidden_module.HiddenDescriptor', - course_dirs=['toy'], - load_error_modules=True, - ) + TEST_DATA_DIR, + default_class='xmodule.hidden_module.HiddenDescriptor', + course_dirs=['toy'], + load_error_modules=True, + ) self.check_pages_load(module_store) def test_full_course_loads(self): module_store = XMLModuleStore( - TEST_DATA_DIR, - default_class='xmodule.hidden_module.HiddenDescriptor', - course_dirs=['full'], - load_error_modules=True, - ) + TEST_DATA_DIR, + default_class='xmodule.hidden_module.HiddenDescriptor', + course_dirs=['full'], + load_error_modules=True, + ) self.check_pages_load(module_store) @@ -525,7 +517,6 @@ class TestViewAuth(PageLoader): print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) - # now also make the instructor staff u = user(self.instructor) u.is_staff = True @@ -536,7 +527,6 @@ class TestViewAuth(PageLoader): print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) - def run_wrapped(self, test): """ test.py turns off start dates. Enable them. @@ -552,7 +542,6 @@ class TestViewAuth(PageLoader): finally: settings.MITX_FEATURES['DISABLE_START_DATES'] = oldDSD - def test_dark_launch(self): """Make sure that before course start, students can't access course pages, but instructors can""" @@ -646,7 +635,6 @@ class TestViewAuth(PageLoader): url = reverse_urls(['courseware'], course)[0] self.check_for_get_code(302, url) - # First, try with an enrolled student print '=== Testing student access....' self.login(self.student, self.password) @@ -761,7 +749,6 @@ class TestViewAuth(PageLoader): self.assertTrue(has_access(student_user, self.toy, 'load')) - @override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) class TestCourseGrader(PageLoader): """Check that a course gets graded properly""" @@ -832,13 +819,12 @@ class TestCourseGrader(PageLoader): kwargs={ 'course_id': self.graded_course.id, 'location': problem_location, - 'dispatch': 'problem_check', } - ) + 'dispatch': 'problem_check', }) resp = self.client.post(modx_url, { 'input_i4x-edX-graded-problem-{0}_2_1'.format(problem_url_name): responses[0], 'input_i4x-edX-graded-problem-{0}_2_2'.format(problem_url_name): responses[1], - }) + }) print "modx_url", modx_url, "responses", responses print "resp", resp @@ -854,8 +840,7 @@ class TestCourseGrader(PageLoader): kwargs={ 'course_id': self.graded_course.id, 'location': problem_location, - 'dispatch': 'problem_reset', } - ) + 'dispatch': 'problem_reset', }) resp = self.client.post(modx_url) return resp