Merge pull request #37474 from openedx/fix-assert-dict-contains-subset-depr

fix: replace deprecated assertDictContainsSubset()
This commit is contained in:
Feanil Patel
2025-10-14 13:42:51 -04:00
committed by GitHub
26 changed files with 362 additions and 210 deletions

View File

@@ -86,6 +86,7 @@ from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import (
add_container_page_publishing_info,
create_xblock_info,
)
from common.test.utils import assert_dict_contains_subset
class AsideTest(XBlockAside):
@@ -863,7 +864,8 @@ class TestDuplicateItem(ItemTest, DuplicateHelper, OpenEdxEventsTestMixin):
XBLOCK_DUPLICATED.connect(event_receiver)
usage_key = self._duplicate_and_verify(self.vert_usage_key, self.seq_usage_key)
event_receiver.assert_called()
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": XBLOCK_DUPLICATED,
"sender": None,

View File

@@ -36,6 +36,7 @@ from openedx.core.djangolib.testing.utils import skip_unless_lms
from xmodule.modulestore.tests.django_utils import \
SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
from common.test.utils import assert_dict_contains_subset
class TestUserProfileEvents(UserSettingsEventTestMixin, TestCase):
@@ -271,7 +272,8 @@ class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
enrollment = CourseEnrollment.enroll(self.user, self.course.id)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_ENROLLMENT_CREATED,
"sender": None,
@@ -294,7 +296,7 @@ class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
creation_date=enrollment.created,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
def test_enrollment_changed_event_emitted(self):
@@ -314,7 +316,8 @@ class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
enrollment.update_enrollment(mode="verified")
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_ENROLLMENT_CHANGED,
"sender": None,
@@ -337,7 +340,7 @@ class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
creation_date=enrollment.created,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
def test_unenrollment_completed_event_emitted(self):
@@ -357,7 +360,8 @@ class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
CourseEnrollment.unenroll(self.user, self.course.id)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_UNENROLLMENT_COMPLETED,
"sender": None,
@@ -380,7 +384,7 @@ class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
creation_date=enrollment.created,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
@@ -430,7 +434,8 @@ class TestCourseAccessRoleEvents(TestCase, OpenEdxEventsTestMixin):
role.add_users(self.user)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_ACCESS_ROLE_ADDED,
"sender": None,
@@ -448,7 +453,7 @@ class TestCourseAccessRoleEvents(TestCase, OpenEdxEventsTestMixin):
role=role._role_name, # pylint: disable=protected-access
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
@ddt.data(
@@ -468,7 +473,8 @@ class TestCourseAccessRoleEvents(TestCase, OpenEdxEventsTestMixin):
role.remove_users(self.user)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_ACCESS_ROLE_REMOVED,
"sender": None,
@@ -486,5 +492,5 @@ class TestCourseAccessRoleEvents(TestCase, OpenEdxEventsTestMixin):
role=role._role_name, # pylint: disable=protected-access
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)

View File

@@ -30,6 +30,7 @@ from openedx.core.djangoapps.user_authn.views.login import login_user
from openedx.features.enterprise_support.tests.factories import EnterpriseCustomerFactory
from .base import IntegrationTestMixin
from common.test.utils import assert_dict_contains_subset
TESTSHIB_ENTITY_ID = "https://idp.testshib.org/idp/shibboleth"
TESTSHIB_METADATA_URL = "https://mock.testshib.org/metadata/testshib-providers.xml"
@@ -402,8 +403,10 @@ class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin
assert msg.startswith("SAML login %s")
assert action_type == "request"
assert idp_name == self.PROVIDER_IDP_SLUG
self.assertDictContainsSubset(
{"idp": idp_name, "auth_entry": "login", "next": expected_next_url}, request_data
assert_dict_contains_subset(
self,
{"idp": idp_name, "auth_entry": "login", "next": expected_next_url},
request_data,
)
assert next_url == expected_next_url
assert "<samlp:AuthnRequest" in xml
@@ -412,7 +415,7 @@ class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin
assert msg.startswith("SAML login %s")
assert action_type == "response"
assert idp_name == self.PROVIDER_IDP_SLUG
self.assertDictContainsSubset({"RelayState": idp_name}, response_data)
assert_dict_contains_subset(self, {"RelayState": idp_name}, response_data)
assert "SAMLResponse" in response_data
assert next_url == expected_next_url
assert "<saml2p:Response" in xml

View File

@@ -6,6 +6,7 @@ import ddt
from common.djangoapps.third_party_auth.identityserver3 import IdentityServer3
from common.djangoapps.third_party_auth.tests import testutil
from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth
from common.test.utils import assert_dict_contains_subset
@skip_unless_thirdpartyauth()
@@ -97,7 +98,8 @@ class IdentityServer3Test(testutil.TestCase):
Test user details fields are mapped to default keys
"""
provider_config = self.configure_identityServer3_provider(enabled=True)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"username": "Edx",
"email": "edxopenid@example.com",
@@ -105,5 +107,5 @@ class IdentityServer3Test(testutil.TestCase):
"last_name": "Openid",
"fullname": "Edx Openid"
},
provider_config.backend_class().get_user_details(self.response)
provider_config.backend_class().get_user_details(self.response),
)

View File

@@ -9,6 +9,7 @@ from oauthlib.common import Request
from common.djangoapps.third_party_auth.lti import LTI_PARAMS_KEY, LTIAuthBackend
from common.djangoapps.third_party_auth.tests.testutil import ThirdPartyAuthTestMixin
from common.test.utils import assert_dict_contains_subset
class UnitTestLTI(unittest.TestCase, ThirdPartyAuthTestMixin):
@@ -55,10 +56,14 @@ class UnitTestLTI(unittest.TestCase, ThirdPartyAuthTestMixin):
lti_max_timestamp_age=10
)
assert parameters
self.assertDictContainsSubset({
'custom_extra': 'parameter',
'user_id': '292832126'
}, parameters)
assert_dict_contains_subset(
self,
{
'custom_extra': 'parameter',
'user_id': '292832126'
},
parameters,
)
def test_validate_lti_valid_request_with_get_params(self):
request = Request(
@@ -72,10 +77,14 @@ class UnitTestLTI(unittest.TestCase, ThirdPartyAuthTestMixin):
lti_max_timestamp_age=10
)
assert parameters
self.assertDictContainsSubset({
'custom_extra': 'parameter',
'user_id': '292832126'
}, parameters)
assert_dict_contains_subset(
self,
{
'custom_extra': 'parameter',
'user_id': '292832126'
},
parameters,
)
def test_validate_lti_old_timestamp(self):
request = Request(

View File

@@ -12,6 +12,15 @@ from django.dispatch import Signal
from markupsafe import escape
def assert_dict_contains_subset(test_case, subset, superset):
"""
Assert that `superset` includes all key/value pairs from `subset`.
"""
test_case.assertTrue(
all(item in superset.items() for item in subset.items())
)
@contextmanager
def nostderr():
"""

View File

@@ -18,6 +18,7 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou
from openedx.core.djangolib.testing.utils import skip_unless_lms
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from common.test.utils import assert_dict_contains_subset
@skip_unless_lms
@@ -94,7 +95,8 @@ class CertificateEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": CERTIFICATE_CREATED,
"sender": None,
@@ -118,7 +120,7 @@ class CertificateEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
name=certificate.name,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
def test_send_certificate_changed_event(self):
@@ -147,7 +149,8 @@ class CertificateEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
certificate.save()
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": CERTIFICATE_CHANGED,
"sender": None,
@@ -171,7 +174,7 @@ class CertificateEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
name=certificate.name,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
def test_send_certificate_revoked_event(self):
@@ -199,7 +202,8 @@ class CertificateEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
certificate.invalidate()
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": CERTIFICATE_REVOKED,
"sender": None,
@@ -223,5 +227,5 @@ class CertificateEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
name=certificate.name,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)

View File

@@ -26,6 +26,7 @@ from ..models import CommerceConfiguration
from ..utils import _generate_refund_notification_body, _send_refund_notification, create_zendesk_ticket
from . import JSON
from .mocks import mock_create_refund, mock_process_refund
from common.test.utils import assert_dict_contains_subset
ZENDESK_URL = 'http://zendesk.example.com/'
ZENDESK_USER = 'test@example.com'
@@ -309,7 +310,7 @@ class TestRefundSignal(ModuleStoreTestCase):
f'{ZENDESK_USER}/token:{ZENDESK_API_KEY}'.encode('utf8')).decode('utf8')
)
}
self.assertDictContainsSubset(expected, last_request.headers)
assert_dict_contains_subset(self, expected, last_request.headers)
# Verify the content
expected = {

View File

@@ -63,6 +63,7 @@ from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
from .test_video_handlers import BaseTestVideoXBlock, TestVideo
from .test_video_xml import SOURCE_XML, PUBLIC_SOURCE_XML
from common.test.utils import assert_dict_contains_subset
TRANSCRIPT_FILE_SRT_DATA = """
1
@@ -1692,7 +1693,8 @@ class TestVideoBlockStudentViewJson(BaseTestVideoXBlock, CacheIsolationTestCase)
"""
Verifies the result is as expected when returning video data from VAL.
"""
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
result.pop("encoded_videos")[self.TEST_PROFILE],
self.TEST_ENCODED_VIDEO,
)
@@ -2057,31 +2059,34 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
assert video_data['encoded_videos'][0]['bitrate'] == 333
# Verify that VAL transcript is imported.
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
self.get_video_transcript_data(
edx_video_id,
language_code=val_transcript_language_code,
provider=val_transcript_provider
),
get_video_transcript(video.edx_video_id, val_transcript_language_code)
get_video_transcript(video.edx_video_id, val_transcript_language_code),
)
# Verify that transcript from sub field is imported.
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
self.get_video_transcript_data(
edx_video_id,
language_code=self.block.transcript_language
),
get_video_transcript(video.edx_video_id, self.block.transcript_language)
get_video_transcript(video.edx_video_id, self.block.transcript_language),
)
# Verify that transcript from transcript field is imported.
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
self.get_video_transcript_data(
edx_video_id,
language_code=external_transcript_language_code
),
get_video_transcript(video.edx_video_id, external_transcript_language_code)
get_video_transcript(video.edx_video_id, external_transcript_language_code),
)
def test_import_no_video_id(self):
@@ -2151,13 +2156,14 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
assert video_data['status'] == 'external'
# Verify that VAL transcript is imported.
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
self.get_video_transcript_data(
edx_video_id,
language_code=val_transcript_language_code,
provider=val_transcript_provider
),
get_video_transcript(video.edx_video_id, val_transcript_language_code)
get_video_transcript(video.edx_video_id, val_transcript_language_code),
)
@ddt.data(
@@ -2292,9 +2298,10 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
assert video_data['status'] == 'external'
# Verify that correct transcripts are imported.
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
expected_transcript,
get_video_transcript(video.edx_video_id, language_code)
get_video_transcript(video.edx_video_id, language_code),
)
def test_import_val_data_invalid(self):

View File

@@ -36,7 +36,7 @@ from common.djangoapps.track.views.tests.base import (
SegmentIOTrackingTestCaseBase,
)
from common.djangoapps.util.testing import UrlResetMixin
from common.test.utils import MockSignalHandlerMixin, disable_signal
from common.test.utils import MockSignalHandlerMixin, disable_signal, assert_dict_contains_subset
from lms.djangoapps.discussion.django_comment_client.base import views
from lms.djangoapps.discussion.django_comment_client.tests.group_id import (
CohortedTopicGroupIdTestMixinV2,
@@ -1873,7 +1873,8 @@ class ForumEventTestCase(
assert name == event_name
assert event["team_id"] == team.team_id
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": forum_event,
"sender": None,
@@ -1959,7 +1960,8 @@ class ForumEventTestCase(
event_receiver.assert_called_once()
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": FORUM_THREAD_RESPONSE_CREATED,
"sender": None,
@@ -2002,7 +2004,8 @@ class ForumEventTestCase(
assert event["user_course_roles"] == ["Wizard"]
assert event["options"]["followed"] is False
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": FORUM_RESPONSE_COMMENT_CREATED,
"sender": None,

View File

@@ -21,6 +21,7 @@ from lms.djangoapps.experiments.models import ExperimentData # lint-amnesty, py
from lms.djangoapps.experiments.serializers import ExperimentDataSerializer
from openedx.core.djangolib.testing.utils import skip_unless_lms
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
from common.test.utils import assert_dict_contains_subset
CROSS_DOMAIN_REFERER = 'https://ecommerce.edx.org'
@@ -42,7 +43,7 @@ class ExperimentDataViewSetTests(APITestCase, ModuleStoreTestCase): # lint-amne
ExperimentData.objects.get(user=user)
data['user'] = user.username
self.assertDictContainsSubset(data, response.data)
assert_dict_contains_subset(self, data, response.data)
def test_list_permissions(self):
""" Users should only be able to list their own data. """

View File

@@ -29,6 +29,7 @@ from lms.djangoapps.grades.models import PersistentCourseGrade
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from common.test.utils import assert_dict_contains_subset
class PersistentGradeEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
@@ -90,7 +91,8 @@ class PersistentGradeEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixi
PERSISTENT_GRADE_SUMMARY_CHANGED.connect(event_receiver)
grade = PersistentCourseGrade.update_or_create(**self.params)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": PERSISTENT_GRADE_SUMMARY_CHANGED,
"sender": None,
@@ -151,7 +153,8 @@ class CoursePassingStatusEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTest
grade_factory.update(self.user, self.course)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_PASSING_STATUS_UPDATED,
"sender": None,
@@ -224,7 +227,8 @@ class CCXCoursePassingStatusEventsTest(
grade_factory.update(self.user, self.store.get_course(self.ccx_locator))
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": CCX_COURSE_PASSING_STATUS_UPDATED,
"sender": None,

View File

@@ -44,6 +44,7 @@ from openedx.core.djangoapps.util.testing import TestConditionalContent
from openedx.core.lib.url_utils import quote_slashes
from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import BlockFactory # lint-amnesty, pylint: disable=wrong-import-order
from common.test.utils import assert_dict_contains_subset
log = logging.getLogger(__name__)
@@ -585,7 +586,7 @@ class TestGradeReportConditionalContent(TestReportMixin, TestConditionalContent,
Arguments:
task_result (dict): Return value of `CourseGradeReport.generate`.
"""
self.assertDictContainsSubset({'attempted': 2, 'succeeded': 2, 'failed': 0}, task_result)
assert_dict_contains_subset(self, {'attempted': 2, 'succeeded': 2, 'failed': 0}, task_result)
def verify_grades_in_csv(self, students_grades, ignore_other_columns=False):
"""

View File

@@ -77,6 +77,7 @@ from xmodule.tests.helpers import override_descriptor_system # pylint: disable=
from ..models import ReportStore
from ..tasks_helper.utils import UPDATE_STATUS_FAILED, UPDATE_STATUS_SUCCEEDED
from common.test.utils import assert_dict_contains_subset
_TEAMS_CONFIG = TeamsConfig({
'max_size': 2,
@@ -97,7 +98,7 @@ class InstructorGradeReportTestCase(TestReportMixin, InstructorTaskCourseTestCas
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'):
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = CourseGradeReport.generate(None, None, course_id, {}, 'graded')
self.assertDictContainsSubset({'attempted': num_rows, 'succeeded': num_rows, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': num_rows, 'succeeded': num_rows, 'failed': 0}, result)
report_store = ReportStore.from_config(config_name='GRADES_DOWNLOAD')
report_csv_filename = report_store.links_for(course_id)[0][0]
report_path = report_store.path_to(course_id, report_csv_filename)
@@ -135,7 +136,7 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase):
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = CourseGradeReport.generate(None, None, self.course.id, {}, 'graded')
num_students = len(emails)
self.assertDictContainsSubset({'attempted': num_students, 'succeeded': num_students, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': num_students, 'succeeded': num_students, 'failed': 0}, result)
@ddt.data(True, False)
@patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task')
@@ -150,7 +151,7 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase):
]
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = CourseGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset({'attempted': 1, 'succeeded': 0, 'failed': 1}, result)
assert_dict_contains_subset(self, {'attempted': 1, 'succeeded': 0, 'failed': 1}, result)
report_store = ReportStore.from_config(config_name='GRADES_DOWNLOAD')
assert any(('grade_report_err' in item[0]) for item in report_store.links_for(self.course.id))
@@ -334,7 +335,7 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase):
)
]
result = CourseGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset({'attempted': 1, 'succeeded': 1, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': 1, 'succeeded': 1, 'failed': 0}, result)
def test_certificate_eligibility(self):
"""
@@ -430,8 +431,10 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase):
self._verify_cell_data_for_user('inactive-student', self.course.id, 'Enrollment Status', NOT_ENROLLED_IN_COURSE)
expected_students = 2
self.assertDictContainsSubset(
{'attempted': expected_students, 'succeeded': expected_students, 'failed': 0}, result
assert_dict_contains_subset(
self,
{'attempted': expected_students, 'succeeded': expected_students, 'failed': 0},
result,
)
@@ -539,12 +542,16 @@ class TestProblemResponsesReport(TestReportMixin, InstructorTaskModuleTestCase):
usage_key_str_list=[str(problem.location)],
)
assert len(student_data) == 1
self.assertDictContainsSubset({
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
}, student_data[0])
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
},
student_data[0],
)
assert 'state' in student_data[0]
assert student_data_keys_list == ['username', 'title', 'location', 'block_key', 'state']
mock_list_problem_responses.assert_called_with(self.course.id, ANY, ANY)
@@ -569,22 +576,30 @@ class TestProblemResponsesReport(TestReportMixin, InstructorTaskModuleTestCase):
usage_key_str_list=[str(self.course.location)],
)
assert len(student_data) == 2
self.assertDictContainsSubset({
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state1',
'more': 'state1!',
}, student_data[0])
self.assertDictContainsSubset({
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state2',
'more': 'state2!',
}, student_data[1])
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state1',
'more': 'state1!',
},
student_data[0],
)
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state2',
'more': 'state2!',
},
student_data[1],
)
assert student_data[0]['state'] == student_data[1]['state']
assert student_data_keys_list == ['username', 'title', 'location', 'more', 'some', 'block_key', 'state']
@@ -610,22 +625,30 @@ class TestProblemResponsesReport(TestReportMixin, InstructorTaskModuleTestCase):
usage_key_str_list=[str(self.course.location)],
)
assert len(student_data) == 2
self.assertDictContainsSubset({
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state1',
'more': 'state1!',
}, student_data[0])
self.assertDictContainsSubset({
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state2',
'more': 'state2!',
}, student_data[1])
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state1',
'more': 'state1!',
},
student_data[0],
)
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'some': 'state2',
'more': 'state2!',
},
student_data[1],
)
assert student_data[0]['state'] == student_data[1]['state']
assert student_data_keys_list == ['username', 'title', 'location', 'some', 'more', 'block_key', 'state']
@@ -642,16 +665,20 @@ class TestProblemResponsesReport(TestReportMixin, InstructorTaskModuleTestCase):
usage_key_str_list=[str(self.course.location)],
)
assert len(student_data) == 1
self.assertDictContainsSubset({
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'Answer ID': 'Problem1_2_1',
'Answer': 'Option 1',
'Correct Answer': 'Option 1',
'Question': 'The correct answer is Option 1',
}, student_data[0])
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': 'test_course > Section > Subsection > Problem1',
'block_key': 'block-v1:edx+1.23x+test_course+type@problem+block@Problem1',
'title': 'Problem1',
'Answer ID': 'Problem1_2_1',
'Answer': 'Option 1',
'Correct Answer': 'Option 1',
'Question': 'The correct answer is Option 1',
},
student_data[0],
)
assert 'state' in student_data[0]
assert student_data_keys_list == ['username', 'title', 'location', 'Answer', 'Answer ID', 'Correct Answer',
'Question', 'block_key', 'state']
@@ -671,16 +698,20 @@ class TestProblemResponsesReport(TestReportMixin, InstructorTaskModuleTestCase):
)
assert len(student_data) == 2
for idx in range(1, 3):
self.assertDictContainsSubset({
'username': 'student',
'location': f'test_course > Section > Subsection > Problem{idx}',
'block_key': f'block-v1:edx+1.23x+test_course+type@problem+block@Problem{idx}',
'title': f'Problem{idx}',
'Answer ID': f'Problem{idx}_2_1',
'Answer': 'Option 1',
'Correct Answer': 'Option 1',
'Question': 'The correct answer is Option 1',
}, student_data[idx - 1])
assert_dict_contains_subset(
self,
{
'username': 'student',
'location': f'test_course > Section > Subsection > Problem{idx}',
'block_key': f'block-v1:edx+1.23x+test_course+type@problem+block@Problem{idx}',
'title': f'Problem{idx}',
'Answer ID': f'Problem{idx}_2_1',
'Answer': 'Option 1',
'Correct Answer': 'Option 1',
'Question': 'The correct answer is Option 1',
},
student_data[idx - 1],
)
assert 'state' in student_data[(idx - 1)]
@ddt.data(
@@ -819,7 +850,11 @@ class TestProblemGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
"""
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = ProblemGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset({'action_name': 'graded', 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 2, 'succeeded': 2, 'failed': 0},
result
)
self.verify_rows_in_csv([
dict(list(zip(
self.csv_header_row,
@@ -845,7 +880,11 @@ class TestProblemGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
self.submit_student_answer(self.student_1.username, 'Problem1', ['Option 1'])
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = ProblemGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset({'action_name': 'graded', 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 2, 'succeeded': 2, 'failed': 0},
result
)
problem_name = 'Homework 1: Subsection - Problem1'
header_row = self.csv_header_row + [problem_name + ' (Earned)', problem_name + ' (Possible)']
self.verify_rows_in_csv([
@@ -891,8 +930,10 @@ class TestProblemGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
self.submit_student_answer(student_verified.username, 'Problem1', ['Option 1'])
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = ProblemGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset(
{'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0}, result
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0},
result,
)
@patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task')
@@ -913,7 +954,11 @@ class TestProblemGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
self.submit_student_answer(self.student_1.username, 'Problem1', ['Option 1'])
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = ProblemGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset({'action_name': 'graded', 'attempted': 3, 'succeeded': 3, 'failed': 0}, result)
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 3, 'succeeded': 3, 'failed': 0},
result
)
problem_name = 'Homework 1: Subsection - Problem1'
header_row = self.csv_header_row + [problem_name + ' (Earned)', problem_name + ' (Possible)']
self.verify_rows_in_csv([
@@ -987,8 +1032,10 @@ class TestProblemReportSplitTestContent(TestReportMixin, TestConditionalContent,
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'):
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = ProblemGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset(
{'action_name': 'graded', 'attempted': 2, 'succeeded': 2, 'failed': 0}, result
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 2, 'succeeded': 2, 'failed': 0},
result,
)
problem_names = ['Homework 1: Subsection - problem_a_url', 'Homework 1: Subsection - problem_b_url']
@@ -1143,8 +1190,10 @@ class TestProblemReportCohortedContent(TestReportMixin, ContentGroupTestCase, In
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'):
with patch(USE_ON_DISK_GRADE_REPORT, return_value=use_tempfile):
result = ProblemGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset(
{'action_name': 'graded', 'attempted': 5, 'succeeded': 5, 'failed': 0}, result
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 5, 'succeeded': 5, 'failed': 0},
result,
)
problem_names = ['Homework 1: Subsection - Problem0', 'Homework 1: Subsection - Problem1']
header_row = ['Student ID', 'Email', 'Username', 'Enrollment Status', 'Grade']
@@ -1228,7 +1277,7 @@ class TestCourseSurveyReport(TestReportMixin, InstructorTaskCourseTestCase):
None, None, self.course.id,
task_input, 'generating course survey report'
)
self.assertDictContainsSubset({'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
def test_generate_course_survey_report(self):
"""
@@ -1262,7 +1311,7 @@ class TestCourseSurveyReport(TestReportMixin, InstructorTaskCourseTestCase):
])
expected_data = [header_row, student1_row, student2_row]
self.assertDictContainsSubset({'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self._verify_csv_file_report(report_store, expected_data)
def _verify_csv_file_report(self, report_store, expected_data):
@@ -1297,7 +1346,7 @@ class TestStudentReport(TestReportMixin, InstructorTaskCourseTestCase):
links = report_store.links_for(self.course.id)
assert len(links) == 1
self.assertDictContainsSubset({'attempted': 1, 'succeeded': 1, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': 1, 'succeeded': 1, 'failed': 0}, result)
def test_custom_directory(self):
self.create_student('student', 'student@example.com')
@@ -1352,7 +1401,7 @@ class TestStudentReport(TestReportMixin, InstructorTaskCourseTestCase):
result = upload_students_csv(None, None, self.course.id, task_input, 'calculated')
# This assertion simply confirms that the generation completed with no errors
num_students = len(students)
self.assertDictContainsSubset({'attempted': num_students, 'succeeded': num_students, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': num_students, 'succeeded': num_students, 'failed': 0}, result)
class TestTeamStudentReport(TestReportMixin, InstructorTaskCourseTestCase):
@@ -1382,7 +1431,7 @@ class TestTeamStudentReport(TestReportMixin, InstructorTaskCourseTestCase):
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task') as mock_current_task:
mock_current_task.return_value = current_task
result = upload_students_csv(None, None, self.course.id, task_input, 'calculated')
self.assertDictContainsSubset({'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
report_store = ReportStore.from_config(config_name='GRADES_DOWNLOAD')
report_csv_filename = report_store.links_for(self.course.id)[0][0]
report_path = report_store.path_to(self.course.id, report_csv_filename)
@@ -1447,7 +1496,7 @@ class TestListMayEnroll(TestReportMixin, InstructorTaskCourseTestCase):
links = report_store.links_for(self.course.id)
assert len(links) == 1
self.assertDictContainsSubset({'attempted': 1, 'succeeded': 1, 'failed': 0}, result)
assert_dict_contains_subset(self, {'attempted': 1, 'succeeded': 1, 'failed': 0}, result)
def test_unicode_email_addresses(self):
"""
@@ -1463,7 +1512,11 @@ class TestListMayEnroll(TestReportMixin, InstructorTaskCourseTestCase):
result = upload_may_enroll_csv(None, None, self.course.id, task_input, 'calculated')
# This assertion simply confirms that the generation completed with no errors
num_enrollments = len(enrollments)
self.assertDictContainsSubset({'attempted': num_enrollments, 'succeeded': num_enrollments, 'failed': 0}, result)
assert_dict_contains_subset(
self,
{'attempted': num_enrollments, 'succeeded': num_enrollments, 'failed': 0},
result
)
class MockDefaultStorage:
@@ -1510,7 +1563,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,,Cohort 1\n'
'student_2,,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1525,7 +1578,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
',student_1@example.com,Cohort 1\n'
',student_2@example.com,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1540,7 +1593,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,student_1@example.com,Cohort 1\n'
'student_2,student_2@example.com,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1561,7 +1614,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,student_1@example.com,Cohort 1\n' # valid username and email
'Invalid,student_2@example.com,Cohort 2' # invalid username, valid email
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1575,7 +1628,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'username,email,cohort\n'
'Invalid,,Cohort 1\n'
)
self.assertDictContainsSubset({'total': 1, 'attempted': 1, 'succeeded': 0, 'failed': 1}, result)
assert_dict_contains_subset(self, {'total': 1, 'attempted': 1, 'succeeded': 0, 'failed': 1}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '0', 'Invalid', '', '']))),
@@ -1589,7 +1642,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
',student_1@example.com,Does Not Exist\n'
'student_2,,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 1, 'failed': 1}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 1, 'failed': 1}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Does Not Exist', 'False', '0', '', '', '']))),
@@ -1603,8 +1656,11 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'username,email,cohort\n'
',example_email@example.com,Cohort 1'
)
self.assertDictContainsSubset({'total': 1, 'attempted': 1, 'succeeded': 0, 'failed': 0},
result)
assert_dict_contains_subset(
self,
{'total': 1, 'attempted': 1, 'succeeded': 0, 'failed': 0},
result,
)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '0', '', '', 'example_email@example.com']))),
@@ -1617,7 +1673,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'username,email,cohort\n'
',student_1@,Cohort 1\n'
)
self.assertDictContainsSubset({'total': 1, 'attempted': 1, 'succeeded': 0, 'failed': 1}, result)
assert_dict_contains_subset(self, {'total': 1, 'attempted': 1, 'succeeded': 0, 'failed': 1}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '0', '', 'student_1@', '']))),
@@ -1642,7 +1698,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,\n'
'student_2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 0, 'failed': 2}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 0, 'failed': 2}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['', 'False', '0', '', '', '']))),
@@ -1654,7 +1710,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
result = self._cohort_students_and_upload(
'username,email,cohort'
)
self.assertDictContainsSubset({'total': 0, 'attempted': 0, 'succeeded': 0, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 0, 'attempted': 0, 'succeeded': 0, 'failed': 0}, result)
self.verify_rows_in_csv([])
def test_carriage_return(self):
@@ -1666,7 +1722,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,,Cohort 1\r'
'student_2,,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1684,7 +1740,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,,Cohort 1\r\n'
'student_2,,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1704,7 +1760,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,,Cohort 2\n'
'student_2,,Cohort 1'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'succeeded': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '1', '', '', '']))),
@@ -1724,7 +1780,7 @@ class TestCohortStudents(TestReportMixin, InstructorTaskCourseTestCase):
'student_1\xec,,Cohort 1\n'
'student_2,,Cohort 2'
)
self.assertDictContainsSubset({'total': 2, 'attempted': 2, 'skipped': 2, 'failed': 0}, result)
assert_dict_contains_subset(self, {'total': 2, 'attempted': 2, 'skipped': 2, 'failed': 0}, result)
self.verify_rows_in_csv(
[
dict(list(zip(self.csv_header_row, ['Cohort 1', 'True', '0', '', '', '']))),
@@ -1809,7 +1865,8 @@ class TestGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'):
result = CourseGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0},
result,
)
@@ -1868,7 +1925,8 @@ class TestGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'):
result = CourseGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0},
result,
)
@@ -1912,8 +1970,10 @@ class TestGradeReport(TestReportMixin, InstructorTaskModuleTestCase):
self.submit_student_answer(student_1.username, 'Problem4', ['Option 1'])
self.submit_student_answer(student_verified.username, 'Problem4', ['Option 1'])
result = CourseGradeReport.generate(None, None, self.course.id, {}, 'graded')
self.assertDictContainsSubset(
{'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0}, result
assert_dict_contains_subset(
self,
{'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0},
result,
)
@ddt.data(True, False)
@@ -2517,9 +2577,10 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
None, None, self.course.id, task_input, 'certificates generated'
)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
expected_results,
result
result,
)
def _create_students(self, number_of_students):

View File

@@ -52,7 +52,7 @@ from common.djangoapps.student.tests.factories import (
UserFactory,
)
from common.djangoapps.third_party_auth.tests.factories import SAMLProviderConfigFactory
from common.test.utils import disable_signal
from common.test.utils import disable_signal, assert_dict_contains_subset
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
from lms.djangoapps.support.models import CourseResetAudit
from lms.djangoapps.support.serializers import ProgramEnrollmentSerializer
@@ -343,14 +343,18 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
assert response.status_code == 200
data = json.loads(response.content.decode('utf-8'))
assert len(data) == 1
self.assertDictContainsSubset({
'mode': CourseMode.AUDIT,
'manual_enrollment': {},
'user': self.student.username,
'course_id': str(self.course.id),
'is_active': True,
'verified_upgrade_deadline': None,
}, data[0])
assert_dict_contains_subset(
self,
{
'mode': CourseMode.AUDIT,
'manual_enrollment': {},
'user': self.student.username,
'course_id': str(self.course.id),
'is_active': True,
'verified_upgrade_deadline': None,
},
data[0],
)
assert {CourseMode.VERIFIED, CourseMode.AUDIT, CourseMode.HONOR, CourseMode.NO_ID_PROFESSIONAL_MODE,
CourseMode.PROFESSIONAL, CourseMode.CREDIT_MODE} == {mode['slug'] for mode in data[0]['course_modes']}
assert 'enterprise_course_enrollments' not in data[0]
@@ -471,10 +475,14 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
)
response = self.client.get(self.url)
assert response.status_code == 200
self.assertDictContainsSubset({
'enrolled_by': self.user.email,
'reason': 'Financial Assistance',
}, json.loads(response.content.decode('utf-8'))[0]['manual_enrollment'])
assert_dict_contains_subset(
self,
{
'enrolled_by': self.user.email,
'reason': 'Financial Assistance',
},
json.loads(response.content.decode('utf-8'))[0]['manual_enrollment'],
)
@disable_signal(signals, 'post_save')
@ddt.data('username', 'email')

View File

@@ -27,6 +27,7 @@ from openedx.core.djangoapps.xblock import api as xblock_api
from openedx.core.djangolib.testing.utils import skip_unless_lms, skip_unless_cms
from openedx.core.lib.xblock_serializer import api as serializer_api
from common.djangoapps.student.tests.factories import UserFactory
from common.test.utils import assert_dict_contains_subset
class ContentLibraryContentTestMixin:
@@ -205,10 +206,14 @@ class ContentLibraryRuntimeTests(ContentLibraryContentTestMixin, TestCase):
assert metadata_view_result.data['display_name'] == 'New Multi Choice Question'
assert 'children' not in metadata_view_result.data
assert 'editable_children' not in metadata_view_result.data
self.assertDictContainsSubset({
"content_type": "CAPA",
"problem_types": ["multiplechoiceresponse"],
}, metadata_view_result.data["index_dictionary"])
assert_dict_contains_subset(
self,
{
"content_type": "CAPA",
"problem_types": ["multiplechoiceresponse"],
},
metadata_view_result.data["index_dictionary"],
)
assert metadata_view_result.data['student_view_data'] is None
# Capa doesn't provide student_view_data
@@ -493,11 +498,15 @@ class ContentLibraryXBlockUserStateTest(ContentLibraryContentTestMixin, TestCase
submit_result = client.post(problem_check_url, data={problem_key: "choice_3"})
assert submit_result.status_code == 200
submit_data = json.loads(submit_result.content.decode('utf-8'))
self.assertDictContainsSubset({
"current_score": 0,
"total_possible": 1,
"attempts_used": 1,
}, submit_data)
assert_dict_contains_subset(
self,
{
"current_score": 0,
"total_possible": 1,
"attempts_used": 1,
},
submit_data,
)
# Now test that the score is also persisted in StudentModule:
# If we add a REST API to get an individual block's score, that should be checked instead of StudentModule.
@@ -509,11 +518,15 @@ class ContentLibraryXBlockUserStateTest(ContentLibraryContentTestMixin, TestCase
submit_result = client.post(problem_check_url, data={problem_key: "choice_1"})
assert submit_result.status_code == 200
submit_data = json.loads(submit_result.content.decode('utf-8'))
self.assertDictContainsSubset({
"current_score": 1,
"total_possible": 1,
"attempts_used": 2,
}, submit_data)
assert_dict_contains_subset(
self,
{
"current_score": 1,
"total_possible": 1,
"attempts_used": 2,
},
submit_data,
)
# Now test that the score is also updated in StudentModule:
# If we add a REST API to get an individual block's score, that should be checked instead of StudentModule.
sm = get_score(self.student_a, block_id)

View File

@@ -18,6 +18,7 @@ from openedx.core.djangolib.testing.utils import skip_unless_lms
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from common.test.utils import assert_dict_contains_subset
@skip_unless_lms
@@ -90,7 +91,8 @@ class CohortEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COHORT_MEMBERSHIP_CHANGED,
"sender": None,
@@ -110,5 +112,5 @@ class CohortEventTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin):
name=cohort_membership.course_user_group.name,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)

View File

@@ -11,6 +11,7 @@ from edx_rest_framework_extensions.auth.jwt.decoder import (
from jwt.exceptions import ExpiredSignatureError
from common.djangoapps.student.models import UserProfile, anonymous_id_for_user
from common.test.utils import assert_dict_contains_subset
class AccessTokenMixin:
@@ -88,7 +89,7 @@ class AccessTokenMixin:
expected['grant_type'] = grant_type or ''
self.assertDictContainsSubset(expected, payload)
assert_dict_contains_subset(self, expected, payload)
if expires_in:
assert payload['exp'] == payload['iat'] + expires_in

View File

@@ -9,6 +9,7 @@ from django.test import TestCase
from oauth2_provider.models import AccessToken
from common.djangoapps.student.tests.factories import UserFactory
from common.test.utils import assert_dict_contains_subset
OAUTH_PROVIDER_ENABLED = settings.FEATURES.get('ENABLE_OAUTH2_PROVIDER')
if OAUTH_PROVIDER_ENABLED:
@@ -43,7 +44,8 @@ class TestOAuthDispatchAPI(TestCase):
token = api.create_dot_access_token(HttpRequest(), self.user, self.client)
assert token['access_token']
assert token['refresh_token']
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
'token_type': 'Bearer',
'expires_in': EXPECTED_DEFAULT_EXPIRES_IN,
@@ -63,5 +65,5 @@ class TestOAuthDispatchAPI(TestCase):
token = api.create_dot_access_token(
HttpRequest(), self.user, self.client, expires_in=expires_in, scopes=['profile'],
)
self.assertDictContainsSubset({'scope': 'profile'}, token)
self.assertDictContainsSubset({'expires_in': expires_in}, token)
assert_dict_contains_subset(self, {'scope': 'profile'}, token)
assert_dict_contains_subset(self, {'expires_in': expires_in}, token)

View File

@@ -12,6 +12,7 @@ from openedx.core.djangoapps.oauth_dispatch.adapters import DOTAdapter
from openedx.core.djangoapps.oauth_dispatch.models import RestrictedApplication
from openedx.core.djangoapps.oauth_dispatch.tests.mixins import AccessTokenMixin
from common.djangoapps.student.tests.factories import UserFactory
from common.test.utils import assert_dict_contains_subset
@ddt.ddt
@@ -171,7 +172,7 @@ class TestCreateJWTs(AccessTokenMixin, TestCase):
token_payload = self.assert_valid_jwt_access_token(
jwt_token, self.user, self.default_scopes, aud=aud, secret=secret,
)
self.assertDictContainsSubset(additional_claims, token_payload)
assert_dict_contains_subset(self, additional_claims, token_payload)
assert user_email_verified == token_payload['email_verified']
assert token_payload['roles'] == mock_create_roles.return_value

View File

@@ -21,6 +21,7 @@ from openedx.core.djangoapps.django_comment_common.models import (
)
from openedx.core.djangoapps.django_comment_common.utils import seed_permissions_roles
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from common.test.utils import assert_dict_contains_subset
class AutoAuthTestCase(UrlResetMixin, TestCase):
@@ -182,12 +183,13 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase, ModuleStoreTestCase):
for key in ['created_status', 'username', 'email', 'password', 'user_id', 'anonymous_id']:
assert key in response_data
user = User.objects.get(username=response_data['username'])
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
'created_status': 'Logged in',
'anonymous_id': anonymous_id_for_user(user, None),
},
response_data
response_data,
)
@ddt.data(*COURSE_IDS_DDT)

View File

@@ -18,6 +18,7 @@ from openedx_events.tests.utils import OpenEdxEventsTestMixin
from common.djangoapps.student.tests.factories import UserFactory, UserProfileFactory
from openedx.core.djangoapps.user_api.tests.test_views import UserAPITestCase
from openedx.core.djangolib.testing.utils import skip_unless_lms
from common.test.utils import assert_dict_contains_subset
@skip_unless_lms
@@ -83,7 +84,8 @@ class RegistrationEventTest(UserAPITestCase, OpenEdxEventsTestMixin):
user = User.objects.get(username=self.user_info.get("username"))
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": STUDENT_REGISTRATION_COMPLETED,
"sender": None,
@@ -97,7 +99,7 @@ class RegistrationEventTest(UserAPITestCase, OpenEdxEventsTestMixin):
is_active=user.is_active,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
@@ -165,7 +167,8 @@ class LoginSessionEventTest(UserAPITestCase, OpenEdxEventsTestMixin):
user = User.objects.get(username=self.user.username)
self.assertTrue(self.receiver_called)
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": SESSION_LOGIN_COMPLETED,
"sender": None,
@@ -179,5 +182,5 @@ class LoginSessionEventTest(UserAPITestCase, OpenEdxEventsTestMixin):
is_active=user.is_active,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)

View File

@@ -44,6 +44,7 @@ from openedx.core.lib.api.test_utils import ApiTestCase
from openedx.features.enterprise_support.tests.factories import EnterpriseCustomerUserFactory
from common.djangoapps.student.models import LoginFailures
from common.djangoapps.util.password_policy_validators import DEFAULT_MAX_PASSWORD_LENGTH
from common.test.utils import assert_dict_contains_subset
@ddt.ddt
@@ -544,7 +545,7 @@ class LoginTest(SiteMixin, CacheIsolationTestCase, OpenEdxEventsTestMixin):
expected = {
'target': '/',
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
@patch.dict("django.conf.settings.FEATURES", {'SQUELCH_PII_IN_LOGS': True})
def test_logout_logging_no_pii(self):

View File

@@ -14,6 +14,7 @@ from django.urls import reverse
from openedx.core.djangoapps.oauth_dispatch.tests.factories import ApplicationFactory
from openedx.core.djangolib.testing.utils import skip_unless_lms
from common.djangoapps.student.tests.factories import UserFactory
from common.test.utils import assert_dict_contains_subset
@skip_unless_lms
@@ -76,14 +77,14 @@ class LogoutTests(TestCase):
expected = {
'target': urllib.parse.unquote(redirect_url),
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
def test_no_redirect_supplied(self):
response = self.client.get(reverse('logout'), HTTP_HOST='testserver')
expected = {
'target': '/',
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
@ddt.data(
('https://www.amazon.org', 'edx.org'),
@@ -100,7 +101,7 @@ class LogoutTests(TestCase):
expected = {
'target': '/',
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
def test_client_logout(self):
""" Verify the context includes a list of the logout URIs of the authenticated OpenID Connect clients.
@@ -113,7 +114,7 @@ class LogoutTests(TestCase):
'logout_uris': [],
'target': '/',
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
@mock.patch(
'django.conf.settings.IDA_LOGOUT_URI_LIST',
@@ -138,7 +139,7 @@ class LogoutTests(TestCase):
'logout_uris': expected_logout_uris,
'target': '/',
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
@mock.patch(
'django.conf.settings.IDA_LOGOUT_URI_LIST',
@@ -161,7 +162,7 @@ class LogoutTests(TestCase):
'logout_uris': expected_logout_uris,
'target': '/',
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
def test_filter_referring_service(self):
""" Verify that, if the user is directed to the logout page from a service, that service's logout URL
@@ -174,7 +175,7 @@ class LogoutTests(TestCase):
'target': '/',
'show_tpa_logout_link': False,
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
def test_learner_portal_logout_having_idp_logout_url(self):
"""
@@ -194,7 +195,7 @@ class LogoutTests(TestCase):
'tpa_logout_url': idp_logout_url,
'show_tpa_logout_link': True,
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
@mock.patch('django.conf.settings.TPA_AUTOMATIC_LOGOUT_ENABLED', True)
def test_automatic_tpa_logout_url_redirect(self):
@@ -214,7 +215,7 @@ class LogoutTests(TestCase):
expected = {
'target': idp_logout_url,
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
@mock.patch('django.conf.settings.TPA_AUTOMATIC_LOGOUT_ENABLED', True)
def test_no_automatic_tpa_logout_without_logout_url(self):
@@ -241,4 +242,4 @@ class LogoutTests(TestCase):
expected = {
'target': nh3.clean(urllib.parse.unquote(redirect_url)),
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)

View File

@@ -19,6 +19,7 @@ from openedx.features.enterprise_support.tests import (
factories
)
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseServiceMockMixin
from common.test.utils import assert_dict_contains_subset
@ddt.ddt
@@ -60,7 +61,7 @@ class EnterpriseLogoutTests(EnterpriseServiceMockMixin, CacheIsolationTestCase,
expected = {
'enterprise_target': enterprise_target,
}
self.assertDictContainsSubset(expected, response.context_data)
assert_dict_contains_subset(self, expected, response.context_data)
if enterprise_target:
self.assertContains(response, 'We are signing you in.')

View File

@@ -63,6 +63,7 @@ from xmodule.modulestore.xml_exporter import export_course_to_xml
from xmodule.modulestore.xml_importer import LocationMixin, import_course_from_xml
from xmodule.tests import DATA_DIR, CourseComparisonTest
from xmodule.x_module import XModuleMixin
from common.test.utils import assert_dict_contains_subset
if not settings.configured:
settings.configure()
@@ -813,7 +814,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
event_receiver.assert_called()
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": COURSE_CREATED,
"sender": None,
@@ -821,7 +823,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
course_key=test_course.id,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
@ddt.data(ModuleStoreEnum.Type.split)
@@ -891,7 +893,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self.store.publish(sequential.location, self.user_id)
event_receiver.assert_called()
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": XBLOCK_PUBLISHED,
"sender": None,
@@ -900,7 +903,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
block_type=sequential.location.block_type,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
@ddt.data(ModuleStoreEnum.Type.split)
@@ -925,7 +928,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
self.store.delete_item(vertical.location, self.user_id)
event_receiver.assert_called()
self.assertDictContainsSubset(
assert_dict_contains_subset(
self,
{
"signal": XBLOCK_DELETED,
"sender": None,
@@ -934,7 +938,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
block_type=vertical.location.block_type,
),
},
event_receiver.call_args.kwargs
event_receiver.call_args.kwargs,
)
def setup_has_changes(self, default_ms):