Commit 9d74b4d2 by John Eskew

Merge pull request #11700 from edx/jeskew/my_unittest_speedups

Unit test speedups - Add context manager to SharedModuleStoreTestCase.
parents 9de6b912 b777530d
...@@ -4,6 +4,7 @@ Modulestore configuration for test cases. ...@@ -4,6 +4,7 @@ Modulestore configuration for test cases.
""" """
import functools import functools
from uuid import uuid4 from uuid import uuid4
from contextlib import contextmanager
from mock import patch from mock import patch
...@@ -267,9 +268,10 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -267,9 +268,10 @@ class SharedModuleStoreTestCase(TestCase):
MODULESTORE = mixed_store_config(mkdtemp_clean(), {}, include_xml=False) MODULESTORE = mixed_store_config(mkdtemp_clean(), {}, include_xml=False)
@classmethod @classmethod
def setUpClass(cls): def _setUpModuleStore(cls): # pylint: disable=invalid-name
super(SharedModuleStoreTestCase, cls).setUpClass() """
Set up the modulestore for an entire test class.
"""
cls._settings_override = override_settings(MODULESTORE=cls.MODULESTORE) cls._settings_override = override_settings(MODULESTORE=cls.MODULESTORE)
cls._settings_override.__enter__() cls._settings_override.__enter__()
XMODULE_FACTORY_LOCK.enable() XMODULE_FACTORY_LOCK.enable()
...@@ -277,6 +279,40 @@ class SharedModuleStoreTestCase(TestCase): ...@@ -277,6 +279,40 @@ class SharedModuleStoreTestCase(TestCase):
cls.store = modulestore() cls.store = modulestore()
@classmethod @classmethod
@contextmanager
def setUpClassAndTestData(cls): # pylint: disable=invalid-name
"""
For use when the test class has a setUpTestData() method that uses variables
that are setup during setUpClass() of the same test class.
Use it like so:
@classmethod
def setUpClass(cls):
with super(MyTestClass, cls).setUpClassAndTestData():
<all the cls.setUpClass() setup code that performs modulestore setup...>
@classmethod
def setUpTestData(cls):
<all the setup code that creates Django models per test class...>
<these models can use variables (courses) setup in setUpClass() above>
"""
cls._setUpModuleStore()
# Now yield to allow the test class to run its setUpClass() setup code.
yield
# Now call the base class, which calls back into the test class's setUpTestData().
super(SharedModuleStoreTestCase, cls).setUpClass()
@classmethod
def setUpClass(cls):
"""
For use when the test class has no setUpTestData() method -or-
when that method does not use variable set up in setUpClass().
"""
super(SharedModuleStoreTestCase, cls).setUpClass()
cls._setUpModuleStore()
@classmethod
def tearDownClass(cls): def tearDownClass(cls):
drop_mongo_collections() # pylint: disable=no-value-for-parameter drop_mongo_collections() # pylint: disable=no-value-for-parameter
clear_all_caches() clear_all_caches()
......
...@@ -25,16 +25,12 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase): ...@@ -25,16 +25,12 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestCCXModulestoreWrapper, cls).setUpClass() super(TestCCXModulestoreWrapper, cls).setUpClass()
cls.course = course = CourseFactory.create() cls.course = CourseFactory.create()
cls.mooc_start = start = datetime.datetime( start = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=pytz.UTC)
2010, 5, 12, 2, 42, tzinfo=pytz.UTC due = datetime.datetime(2010, 7, 7, 0, 0, tzinfo=pytz.UTC)
)
cls.mooc_due = due = datetime.datetime(
2010, 7, 7, 0, 0, tzinfo=pytz.UTC
)
# Create a course outline # Create a course outline
cls.chapters = chapters = [ cls.chapters = chapters = [
ItemFactory.create(start=start, parent=course) for _ in xrange(2) ItemFactory.create(start=start, parent=cls.course) for _ in xrange(2)
] ]
cls.sequentials = sequentials = [ cls.sequentials = sequentials = [
ItemFactory.create(parent=c) for _ in xrange(2) for c in chapters ItemFactory.create(parent=c) for _ in xrange(2) for c in chapters
...@@ -48,20 +44,24 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase): ...@@ -48,20 +44,24 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
ItemFactory.create(parent=v, category='html') for _ in xrange(2) for v in verticals ItemFactory.create(parent=v, category='html') for _ in xrange(2) for v in verticals
] ]
@classmethod
def setUpTestData(cls):
"""
Set up models for the whole TestCase.
"""
cls.user = UserFactory.create()
# Create instructor account
cls.coach = AdminFactory.create()
def setUp(self): def setUp(self):
""" """
Set up tests Set up tests
""" """
super(TestCCXModulestoreWrapper, self).setUp() super(TestCCXModulestoreWrapper, self).setUp()
self.user = UserFactory.create()
# Create instructor account
coach = AdminFactory.create()
self.ccx = ccx = CustomCourseForEdX( self.ccx = ccx = CustomCourseForEdX(
course_id=self.course.id, course_id=self.course.id,
display_name='Test CCX', display_name='Test CCX',
coach=coach coach=self.coach
) )
ccx.save() ccx.save()
...@@ -132,6 +132,7 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase): ...@@ -132,6 +132,7 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
def test_publication_api(self): def test_publication_api(self):
"""verify that we can correctly discern a published item by ccx key""" """verify that we can correctly discern a published item by ccx key"""
with self.store.bulk_operations(self.ccx_locator):
for expected in self.blocks: for expected in self.blocks:
block_key = self.ccx_locator.make_usage_key( block_key = self.ccx_locator.make_usage_key(
expected.location.block_type, expected.location.block_id expected.location.block_type, expected.location.block_id
......
...@@ -7,7 +7,7 @@ from nose.plugins.attrib import attr ...@@ -7,7 +7,7 @@ from nose.plugins.attrib import attr
from django.test.utils import override_settings from django.test.utils import override_settings
from xblock.field_data import DictFieldData from xblock.field_data import DictFieldData
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from ..field_overrides import ( from ..field_overrides import (
disable_overrides, disable_overrides,
...@@ -23,14 +23,21 @@ TESTUSER = "testuser" ...@@ -23,14 +23,21 @@ TESTUSER = "testuser"
@attr('shard_1') @attr('shard_1')
@override_settings(FIELD_OVERRIDE_PROVIDERS=( @override_settings(FIELD_OVERRIDE_PROVIDERS=(
'courseware.tests.test_field_overrides.TestOverrideProvider',)) 'courseware.tests.test_field_overrides.TestOverrideProvider',))
class OverrideFieldDataTests(ModuleStoreTestCase): class OverrideFieldDataTests(SharedModuleStoreTestCase):
""" """
Tests for `OverrideFieldData`. Tests for `OverrideFieldData`.
""" """
@classmethod
def setUpClass(cls):
"""
Course is created here and shared by all the class's tests.
"""
super(OverrideFieldDataTests, cls).setUpClass()
cls.course = CourseFactory.create(enable_ccx=True)
def setUp(self): def setUp(self):
super(OverrideFieldDataTests, self).setUp() super(OverrideFieldDataTests, self).setUp()
self.course = CourseFactory.create(enable_ccx=True)
OverrideFieldData.provider_classes = None OverrideFieldData.provider_classes = None
def tearDown(self): def tearDown(self):
......
...@@ -200,7 +200,7 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase): ...@@ -200,7 +200,7 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TeamAPITestCase, cls).setUpClass() with super(TeamAPITestCase, cls).setUpClassAndTestData():
teams_configuration_1 = { teams_configuration_1 = {
'topics': 'topics':
[ [
...@@ -246,43 +246,44 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase): ...@@ -246,43 +246,44 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
teams_configuration=teams_configuration_2 teams_configuration=teams_configuration_2
) )
def setUp(self): @classmethod
super(TeamAPITestCase, self).setUp() def setUpTestData(cls):
self.topics_count = 4 super(TeamAPITestCase, cls).setUpTestData()
self.users = { cls.topics_count = 4
'staff': AdminFactory.create(password=self.test_password), cls.users = {
'course_staff': StaffFactory.create(course_key=self.test_course_1.id, password=self.test_password) 'staff': AdminFactory.create(password=cls.test_password),
'course_staff': StaffFactory.create(course_key=cls.test_course_1.id, password=cls.test_password)
} }
self.create_and_enroll_student(username='student_enrolled') cls.create_and_enroll_student(username='student_enrolled')
self.create_and_enroll_student(username='student_enrolled_not_on_team') cls.create_and_enroll_student(username='student_enrolled_not_on_team')
self.create_and_enroll_student(username='student_unenrolled', courses=[]) cls.create_and_enroll_student(username='student_unenrolled', courses=[])
# Make this student a community TA. # Make this student a community TA.
self.create_and_enroll_student(username='community_ta') cls.create_and_enroll_student(username='community_ta')
seed_permissions_roles(self.test_course_1.id) seed_permissions_roles(cls.test_course_1.id)
community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA, course_id=self.test_course_1.id) community_ta_role = Role.objects.get(name=FORUM_ROLE_COMMUNITY_TA, course_id=cls.test_course_1.id)
community_ta_role.users.add(self.users['community_ta']) community_ta_role.users.add(cls.users['community_ta'])
# This student is enrolled in both test courses and is a member of a team in each course, but is not on the # This student is enrolled in both test courses and is a member of a team in each course, but is not on the
# same team as student_enrolled. # same team as student_enrolled.
self.create_and_enroll_student( cls.create_and_enroll_student(
courses=[self.test_course_1, self.test_course_2], courses=[cls.test_course_1, cls.test_course_2],
username='student_enrolled_both_courses_other_team' username='student_enrolled_both_courses_other_team'
) )
# Make this student have a public profile # Make this student have a public profile
self.create_and_enroll_student( cls.create_and_enroll_student(
courses=[self.test_course_2], courses=[cls.test_course_2],
username='student_enrolled_public_profile' username='student_enrolled_public_profile'
) )
profile = self.users['student_enrolled_public_profile'].profile profile = cls.users['student_enrolled_public_profile'].profile
profile.year_of_birth = 1970 profile.year_of_birth = 1970
profile.save() profile.save()
# This student is enrolled in the other course, but not yet a member of a team. This is to allow # This student is enrolled in the other course, but not yet a member of a team. This is to allow
# course_2 to use a max_team_size of 1 without breaking other tests on course_1 # course_2 to use a max_team_size of 1 without breaking other tests on course_1
self.create_and_enroll_student( cls.create_and_enroll_student(
courses=[self.test_course_2], courses=[cls.test_course_2],
username='student_enrolled_other_course_not_on_team' username='student_enrolled_other_course_not_on_team'
) )
...@@ -292,58 +293,58 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase): ...@@ -292,58 +293,58 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
sender=CourseTeam, sender=CourseTeam,
dispatch_uid='teams.signals.course_team_post_save_callback' dispatch_uid='teams.signals.course_team_post_save_callback'
): ):
self.solar_team = CourseTeamFactory.create( cls.solar_team = CourseTeamFactory.create(
name=u'Sólar team', name=u'Sólar team',
course_id=self.test_course_1.id, course_id=cls.test_course_1.id,
topic_id='topic_0' topic_id='topic_0'
) )
self.wind_team = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id) cls.wind_team = CourseTeamFactory.create(name='Wind Team', course_id=cls.test_course_1.id)
self.nuclear_team = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id) cls.nuclear_team = CourseTeamFactory.create(name='Nuclear Team', course_id=cls.test_course_1.id)
self.another_team = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id) cls.another_team = CourseTeamFactory.create(name='Another Team', course_id=cls.test_course_2.id)
self.public_profile_team = CourseTeamFactory.create( cls.public_profile_team = CourseTeamFactory.create(
name='Public Profile Team', name='Public Profile Team',
course_id=self.test_course_2.id, course_id=cls.test_course_2.id,
topic_id='topic_6' topic_id='topic_6'
) )
self.search_team = CourseTeamFactory.create( cls.search_team = CourseTeamFactory.create(
name='Search', name='Search',
description='queryable text', description='queryable text',
country='GS', country='GS',
language='to', language='to',
course_id=self.test_course_2.id, course_id=cls.test_course_2.id,
topic_id='topic_7' topic_id='topic_7'
) )
self.chinese_team = CourseTeamFactory.create( cls.chinese_team = CourseTeamFactory.create(
name=u'著文企臺個', name=u'著文企臺個',
description=u'共樣地面較,件展冷不護者這與民教過住意,國制銀產物助音是勢一友', description=u'共樣地面較,件展冷不護者這與民教過住意,國制銀產物助音是勢一友',
country='CN', country='CN',
language='zh_HANS', language='zh_HANS',
course_id=self.test_course_2.id, course_id=cls.test_course_2.id,
topic_id='topic_7' topic_id='topic_7'
) )
self.test_team_name_id_map = {team.name: team for team in ( cls.test_team_name_id_map = {team.name: team for team in (
self.solar_team, cls.solar_team,
self.wind_team, cls.wind_team,
self.nuclear_team, cls.nuclear_team,
self.another_team, cls.another_team,
self.public_profile_team, cls.public_profile_team,
self.search_team, cls.search_team,
self.chinese_team, cls.chinese_team,
)} )}
for user, course in [('staff', self.test_course_1), ('course_staff', self.test_course_1)]: for user, course in [('staff', cls.test_course_1), ('course_staff', cls.test_course_1)]:
CourseEnrollment.enroll( CourseEnrollment.enroll(
self.users[user], course.id, check_access=True cls.users[user], course.id, check_access=True
) )
# Django Rest Framework v3 requires us to pass a request to serializers # Django Rest Framework v3 requires us to pass a request to serializers
# that have URL fields. Since we're invoking this code outside the context # that have URL fields. Since we're invoking this code outside the context
# of a request, we need to simulate that there's a request. # of a request, we need to simulate that there's a request.
self.solar_team.add_user(self.users['student_enrolled']) cls.solar_team.add_user(cls.users['student_enrolled'])
self.nuclear_team.add_user(self.users['student_enrolled_both_courses_other_team']) cls.nuclear_team.add_user(cls.users['student_enrolled_both_courses_other_team'])
self.another_team.add_user(self.users['student_enrolled_both_courses_other_team']) cls.another_team.add_user(cls.users['student_enrolled_both_courses_other_team'])
self.public_profile_team.add_user(self.users['student_enrolled_public_profile']) cls.public_profile_team.add_user(cls.users['student_enrolled_public_profile'])
def build_membership_data_raw(self, username, team): def build_membership_data_raw(self, username, team):
"""Assembles a membership creation payload based on the raw values provided.""" """Assembles a membership creation payload based on the raw values provided."""
...@@ -353,21 +354,22 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase): ...@@ -353,21 +354,22 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
"""Assembles a membership creation payload based on the username and team model provided.""" """Assembles a membership creation payload based on the username and team model provided."""
return self.build_membership_data_raw(self.users[username].username, team.team_id) return self.build_membership_data_raw(self.users[username].username, team.team_id)
def create_and_enroll_student(self, courses=None, username=None): @classmethod
def create_and_enroll_student(cls, courses=None, username=None):
""" Creates a new student and enrolls that student in the course. """ Creates a new student and enrolls that student in the course.
Adds the new user to the self.users dictionary with the username as the key. Adds the new user to the cls.users dictionary with the username as the key.
Returns the username once the user has been created. Returns the username once the user has been created.
""" """
if username is not None: if username is not None:
user = UserFactory.create(password=self.test_password, username=username) user = UserFactory.create(password=cls.test_password, username=username)
else: else:
user = UserFactory.create(password=self.test_password) user = UserFactory.create(password=cls.test_password)
courses = courses if courses is not None else [self.test_course_1] courses = courses if courses is not None else [cls.test_course_1]
for course in courses: for course in courses:
CourseEnrollment.enroll(user, course.id, check_access=True) CourseEnrollment.enroll(user, course.id, check_access=True)
self.users[user.username] = user cls.users[user.username] = user
return user.username return user.username
......
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