Merge pull request #11700 from edx/jeskew/my_unittest_speedups
Unit test speedups - Add context manager to SharedModuleStoreTestCase.
This commit is contained in:
@@ -4,6 +4,7 @@ Modulestore configuration for test cases.
|
||||
"""
|
||||
import functools
|
||||
from uuid import uuid4
|
||||
from contextlib import contextmanager
|
||||
|
||||
from mock import patch
|
||||
|
||||
@@ -267,15 +268,50 @@ class SharedModuleStoreTestCase(TestCase):
|
||||
MODULESTORE = mixed_store_config(mkdtemp_clean(), {}, include_xml=False)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(SharedModuleStoreTestCase, cls).setUpClass()
|
||||
|
||||
def _setUpModuleStore(cls): # pylint: disable=invalid-name
|
||||
"""
|
||||
Set up the modulestore for an entire test class.
|
||||
"""
|
||||
cls._settings_override = override_settings(MODULESTORE=cls.MODULESTORE)
|
||||
cls._settings_override.__enter__()
|
||||
XMODULE_FACTORY_LOCK.enable()
|
||||
clear_existing_modulestores()
|
||||
cls.store = modulestore()
|
||||
|
||||
@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):
|
||||
drop_mongo_collections() # pylint: disable=no-value-for-parameter
|
||||
|
||||
@@ -25,16 +25,12 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestCCXModulestoreWrapper, cls).setUpClass()
|
||||
cls.course = course = CourseFactory.create()
|
||||
cls.mooc_start = start = datetime.datetime(
|
||||
2010, 5, 12, 2, 42, tzinfo=pytz.UTC
|
||||
)
|
||||
cls.mooc_due = due = datetime.datetime(
|
||||
2010, 7, 7, 0, 0, tzinfo=pytz.UTC
|
||||
)
|
||||
cls.course = CourseFactory.create()
|
||||
start = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=pytz.UTC)
|
||||
due = datetime.datetime(2010, 7, 7, 0, 0, tzinfo=pytz.UTC)
|
||||
# Create a course outline
|
||||
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 = [
|
||||
ItemFactory.create(parent=c) for _ in xrange(2) for c in chapters
|
||||
@@ -48,20 +44,24 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
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):
|
||||
"""
|
||||
Set up tests
|
||||
"""
|
||||
super(TestCCXModulestoreWrapper, self).setUp()
|
||||
self.user = UserFactory.create()
|
||||
|
||||
# Create instructor account
|
||||
coach = AdminFactory.create()
|
||||
|
||||
self.ccx = ccx = CustomCourseForEdX(
|
||||
course_id=self.course.id,
|
||||
display_name='Test CCX',
|
||||
coach=coach
|
||||
coach=self.coach
|
||||
)
|
||||
ccx.save()
|
||||
|
||||
@@ -132,12 +132,13 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
|
||||
def test_publication_api(self):
|
||||
"""verify that we can correctly discern a published item by ccx key"""
|
||||
for expected in self.blocks:
|
||||
block_key = self.ccx_locator.make_usage_key(
|
||||
expected.location.block_type, expected.location.block_id
|
||||
)
|
||||
self.assertTrue(self.store.has_published_version(expected))
|
||||
self.store.unpublish(block_key, self.user.id)
|
||||
self.assertFalse(self.store.has_published_version(expected))
|
||||
self.store.publish(block_key, self.user.id)
|
||||
self.assertTrue(self.store.has_published_version(expected))
|
||||
with self.store.bulk_operations(self.ccx_locator):
|
||||
for expected in self.blocks:
|
||||
block_key = self.ccx_locator.make_usage_key(
|
||||
expected.location.block_type, expected.location.block_id
|
||||
)
|
||||
self.assertTrue(self.store.has_published_version(expected))
|
||||
self.store.unpublish(block_key, self.user.id)
|
||||
self.assertFalse(self.store.has_published_version(expected))
|
||||
self.store.publish(block_key, self.user.id)
|
||||
self.assertTrue(self.store.has_published_version(expected))
|
||||
|
||||
@@ -7,7 +7,7 @@ from nose.plugins.attrib import attr
|
||||
from django.test.utils import override_settings
|
||||
from xblock.field_data import DictFieldData
|
||||
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 (
|
||||
disable_overrides,
|
||||
@@ -23,14 +23,21 @@ TESTUSER = "testuser"
|
||||
@attr('shard_1')
|
||||
@override_settings(FIELD_OVERRIDE_PROVIDERS=(
|
||||
'courseware.tests.test_field_overrides.TestOverrideProvider',))
|
||||
class OverrideFieldDataTests(ModuleStoreTestCase):
|
||||
class OverrideFieldDataTests(SharedModuleStoreTestCase):
|
||||
"""
|
||||
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):
|
||||
super(OverrideFieldDataTests, self).setUp()
|
||||
self.course = CourseFactory.create(enable_ccx=True)
|
||||
OverrideFieldData.provider_classes = None
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
@@ -200,89 +200,90 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TeamAPITestCase, cls).setUpClass()
|
||||
teams_configuration_1 = {
|
||||
'topics':
|
||||
[
|
||||
{
|
||||
'id': 'topic_{}'.format(i),
|
||||
'name': name,
|
||||
'description': 'Description for topic {}.'.format(i)
|
||||
} for i, name in enumerate([u'Sólar power', 'Wind Power', 'Nuclear Power', 'Coal Power'])
|
||||
]
|
||||
}
|
||||
cls.test_course_1 = CourseFactory.create(
|
||||
org='TestX',
|
||||
course='TS101',
|
||||
display_name='Test Course',
|
||||
teams_configuration=teams_configuration_1
|
||||
)
|
||||
with super(TeamAPITestCase, cls).setUpClassAndTestData():
|
||||
teams_configuration_1 = {
|
||||
'topics':
|
||||
[
|
||||
{
|
||||
'id': 'topic_{}'.format(i),
|
||||
'name': name,
|
||||
'description': 'Description for topic {}.'.format(i)
|
||||
} for i, name in enumerate([u'Sólar power', 'Wind Power', 'Nuclear Power', 'Coal Power'])
|
||||
]
|
||||
}
|
||||
cls.test_course_1 = CourseFactory.create(
|
||||
org='TestX',
|
||||
course='TS101',
|
||||
display_name='Test Course',
|
||||
teams_configuration=teams_configuration_1
|
||||
)
|
||||
|
||||
teams_configuration_2 = {
|
||||
'topics':
|
||||
[
|
||||
{
|
||||
'id': 'topic_5',
|
||||
'name': 'Other Interests',
|
||||
'description': 'Description for topic 5.'
|
||||
},
|
||||
{
|
||||
'id': 'topic_6',
|
||||
'name': 'Public Profiles',
|
||||
'description': 'Description for topic 6.'
|
||||
},
|
||||
{
|
||||
'id': 'Topic_6.5',
|
||||
'name': 'Test Accessibility Topic',
|
||||
'description': 'Description for Topic_6.5'
|
||||
},
|
||||
],
|
||||
'max_team_size': 1
|
||||
}
|
||||
cls.test_course_2 = CourseFactory.create(
|
||||
org='MIT',
|
||||
course='6.002x',
|
||||
display_name='Circuits',
|
||||
teams_configuration=teams_configuration_2
|
||||
)
|
||||
teams_configuration_2 = {
|
||||
'topics':
|
||||
[
|
||||
{
|
||||
'id': 'topic_5',
|
||||
'name': 'Other Interests',
|
||||
'description': 'Description for topic 5.'
|
||||
},
|
||||
{
|
||||
'id': 'topic_6',
|
||||
'name': 'Public Profiles',
|
||||
'description': 'Description for topic 6.'
|
||||
},
|
||||
{
|
||||
'id': 'Topic_6.5',
|
||||
'name': 'Test Accessibility Topic',
|
||||
'description': 'Description for Topic_6.5'
|
||||
},
|
||||
],
|
||||
'max_team_size': 1
|
||||
}
|
||||
cls.test_course_2 = CourseFactory.create(
|
||||
org='MIT',
|
||||
course='6.002x',
|
||||
display_name='Circuits',
|
||||
teams_configuration=teams_configuration_2
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super(TeamAPITestCase, self).setUp()
|
||||
self.topics_count = 4
|
||||
self.users = {
|
||||
'staff': AdminFactory.create(password=self.test_password),
|
||||
'course_staff': StaffFactory.create(course_key=self.test_course_1.id, password=self.test_password)
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
super(TeamAPITestCase, cls).setUpTestData()
|
||||
cls.topics_count = 4
|
||||
cls.users = {
|
||||
'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')
|
||||
self.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_enrolled')
|
||||
cls.create_and_enroll_student(username='student_enrolled_not_on_team')
|
||||
cls.create_and_enroll_student(username='student_unenrolled', courses=[])
|
||||
|
||||
# Make this student a community TA.
|
||||
self.create_and_enroll_student(username='community_ta')
|
||||
seed_permissions_roles(self.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.users.add(self.users['community_ta'])
|
||||
cls.create_and_enroll_student(username='community_ta')
|
||||
seed_permissions_roles(cls.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(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
|
||||
# same team as student_enrolled.
|
||||
self.create_and_enroll_student(
|
||||
courses=[self.test_course_1, self.test_course_2],
|
||||
cls.create_and_enroll_student(
|
||||
courses=[cls.test_course_1, cls.test_course_2],
|
||||
username='student_enrolled_both_courses_other_team'
|
||||
)
|
||||
|
||||
# Make this student have a public profile
|
||||
self.create_and_enroll_student(
|
||||
courses=[self.test_course_2],
|
||||
cls.create_and_enroll_student(
|
||||
courses=[cls.test_course_2],
|
||||
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.save()
|
||||
|
||||
# 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
|
||||
self.create_and_enroll_student(
|
||||
courses=[self.test_course_2],
|
||||
cls.create_and_enroll_student(
|
||||
courses=[cls.test_course_2],
|
||||
username='student_enrolled_other_course_not_on_team'
|
||||
)
|
||||
|
||||
@@ -292,58 +293,58 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
|
||||
sender=CourseTeam,
|
||||
dispatch_uid='teams.signals.course_team_post_save_callback'
|
||||
):
|
||||
self.solar_team = CourseTeamFactory.create(
|
||||
cls.solar_team = CourseTeamFactory.create(
|
||||
name=u'Sólar team',
|
||||
course_id=self.test_course_1.id,
|
||||
course_id=cls.test_course_1.id,
|
||||
topic_id='topic_0'
|
||||
)
|
||||
self.wind_team = CourseTeamFactory.create(name='Wind Team', course_id=self.test_course_1.id)
|
||||
self.nuclear_team = CourseTeamFactory.create(name='Nuclear Team', course_id=self.test_course_1.id)
|
||||
self.another_team = CourseTeamFactory.create(name='Another Team', course_id=self.test_course_2.id)
|
||||
self.public_profile_team = CourseTeamFactory.create(
|
||||
cls.wind_team = CourseTeamFactory.create(name='Wind Team', course_id=cls.test_course_1.id)
|
||||
cls.nuclear_team = CourseTeamFactory.create(name='Nuclear Team', course_id=cls.test_course_1.id)
|
||||
cls.another_team = CourseTeamFactory.create(name='Another Team', course_id=cls.test_course_2.id)
|
||||
cls.public_profile_team = CourseTeamFactory.create(
|
||||
name='Public Profile Team',
|
||||
course_id=self.test_course_2.id,
|
||||
course_id=cls.test_course_2.id,
|
||||
topic_id='topic_6'
|
||||
)
|
||||
self.search_team = CourseTeamFactory.create(
|
||||
cls.search_team = CourseTeamFactory.create(
|
||||
name='Search',
|
||||
description='queryable text',
|
||||
country='GS',
|
||||
language='to',
|
||||
course_id=self.test_course_2.id,
|
||||
course_id=cls.test_course_2.id,
|
||||
topic_id='topic_7'
|
||||
)
|
||||
self.chinese_team = CourseTeamFactory.create(
|
||||
cls.chinese_team = CourseTeamFactory.create(
|
||||
name=u'著文企臺個',
|
||||
description=u'共樣地面較,件展冷不護者這與民教過住意,國制銀產物助音是勢一友',
|
||||
country='CN',
|
||||
language='zh_HANS',
|
||||
course_id=self.test_course_2.id,
|
||||
course_id=cls.test_course_2.id,
|
||||
topic_id='topic_7'
|
||||
)
|
||||
|
||||
self.test_team_name_id_map = {team.name: team for team in (
|
||||
self.solar_team,
|
||||
self.wind_team,
|
||||
self.nuclear_team,
|
||||
self.another_team,
|
||||
self.public_profile_team,
|
||||
self.search_team,
|
||||
self.chinese_team,
|
||||
cls.test_team_name_id_map = {team.name: team for team in (
|
||||
cls.solar_team,
|
||||
cls.wind_team,
|
||||
cls.nuclear_team,
|
||||
cls.another_team,
|
||||
cls.public_profile_team,
|
||||
cls.search_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(
|
||||
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
|
||||
# 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.
|
||||
self.solar_team.add_user(self.users['student_enrolled'])
|
||||
self.nuclear_team.add_user(self.users['student_enrolled_both_courses_other_team'])
|
||||
self.another_team.add_user(self.users['student_enrolled_both_courses_other_team'])
|
||||
self.public_profile_team.add_user(self.users['student_enrolled_public_profile'])
|
||||
cls.solar_team.add_user(cls.users['student_enrolled'])
|
||||
cls.nuclear_team.add_user(cls.users['student_enrolled_both_courses_other_team'])
|
||||
cls.another_team.add_user(cls.users['student_enrolled_both_courses_other_team'])
|
||||
cls.public_profile_team.add_user(cls.users['student_enrolled_public_profile'])
|
||||
|
||||
def build_membership_data_raw(self, username, team):
|
||||
"""Assembles a membership creation payload based on the raw values provided."""
|
||||
@@ -353,21 +354,22 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
|
||||
"""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)
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
"""
|
||||
if username is not None:
|
||||
user = UserFactory.create(password=self.test_password, username=username)
|
||||
user = UserFactory.create(password=cls.test_password, username=username)
|
||||
else:
|
||||
user = UserFactory.create(password=self.test_password)
|
||||
courses = courses if courses is not None else [self.test_course_1]
|
||||
user = UserFactory.create(password=cls.test_password)
|
||||
courses = courses if courses is not None else [cls.test_course_1]
|
||||
for course in courses:
|
||||
CourseEnrollment.enroll(user, course.id, check_access=True)
|
||||
self.users[user.username] = user
|
||||
cls.users[user.username] = user
|
||||
|
||||
return user.username
|
||||
|
||||
|
||||
Reference in New Issue
Block a user