def test_intervention_locations_in_use(self): self.client.force_login(self.unicef_staff) url = reverse("locations-gis-in-use") # test with missing country, expect error response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) response = self.client.get("{}?country_id={}".format( reverse("locations-gis-in-use"), self.country.id), user=self.unicef_staff) self.assertEqual(response.status_code, status.HTTP_200_OK) # see if no location are in use yet self.assertEqual(len(response.json()), 0) # add intervention locations and test the response intervention = InterventionFactory(status=Intervention.SIGNED) intervention.flat_locations.add(self.location_no_geom, self.location_with_geom) intervention.save() response = self.client.get("{}?country_id={}".format( reverse("locations-gis-in-use"), self.country.id), user=self.unicef_staff) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( sorted(response.data[0].keys()), ["gateway_id", "id", "level", "name", "p_code", "parent_id"])
def test_send(self): intervention = InterventionFactory(status=Intervention.DRAFT) tz = timezone.get_default_timezone() intervention.created = datetime.datetime(2018, 1, 1, 12, 55, 12, 12345, tzinfo=tz) intervention.save() mock_send = Mock() with patch(self.send_path, mock_send): utils.send_intervention_draft_notification() self.assertEqual(mock_send.call_count, 1)
def test_remap_in_use_validation_failed(self): self.mock_sql.return_value = {"rows": []} intervention = InterventionFactory(status=Intervention.SIGNED) intervention.flat_locations.add(self.remapped_location) intervention.save() with self.assertRaises(tasks.NoRemapInUseException): self._run_validation(self.carto_table.pk)
def test_command(self): send_path = "etools.applications.partners.utils.send_notification_with_template" intervention = InterventionFactory(status=Intervention.DRAFT) tz = timezone.get_default_timezone() intervention.created = datetime.datetime(2018, 1, 1, 12, 55, 12, 12345, tzinfo=tz) intervention.save() mock_send = Mock() with patch(send_path, mock_send): call_command("send_intervention_draft_notification") self.assertEqual(mock_send.call_count, 1)
def test_get(self): partner = PartnerFactory() agreement = AgreementFactory(partner=partner) intervention_1 = InterventionFactory(agreement=agreement) intervention_2 = InterventionFactory(agreement=agreement) intervention_3 = InterventionFactory() res = tags.get_interventions(partner.pk) self.assertIn(intervention_1.number, res) self.assertIn(intervention_2.number, res) self.assertNotIn(intervention_3.number, res)
def test_intervention_terminable_statuses(self): """Interventions in amendment cannot be terminated""" terminable_statuses = [Intervention.SIGNED, Intervention.ACTIVE] for terminable_status in terminable_statuses: intervention = InterventionFactory(status=terminable_status, ) self.assertTrue(transition_to_terminated(intervention)) intervention.in_amendment = True with self.assertRaises(TransitionError): transition_to_terminated(intervention)
class TestGetInterventionContext(BaseTenantTestCase): '''Exercise the tasks' helper function get_intervention_context()''' def setUp(self): super(TestGetInterventionContext, self).setUp() self.intervention = InterventionFactory() self.focal_point_user = UserFactory() def test_simple_intervention(self): '''Exercise get_intervention_context() with a very simple intervention''' result = etools.applications.partners.tasks.get_intervention_context( self.intervention) self.assertIsInstance(result, dict) self.assertEqual( sorted(result.keys()), sorted([ 'number', 'partner', 'start_date', 'url', 'unicef_focal_points' ])) self.assertEqual(result['number'], str(self.intervention)) self.assertEqual(result['partner'], self.intervention.agreement.partner.name) self.assertEqual(result['start_date'], 'None') self.assertEqual( result['url'], 'https://{}/pmp/interventions/{}/details'.format( settings.HOST, self.intervention.id)) self.assertEqual(result['unicef_focal_points'], []) def test_non_trivial_intervention(self): '''Exercise get_intervention_context() with an intervention that has some interesting detail''' self.focal_point_user = get_user_model().objects.first() self.intervention.unicef_focal_points.add(self.focal_point_user) self.intervention.start = datetime.date(2017, 8, 1) self.intervention.save() result = etools.applications.partners.tasks.get_intervention_context( self.intervention) self.assertIsInstance(result, dict) self.assertEqual( sorted(result.keys()), sorted([ 'number', 'partner', 'start_date', 'url', 'unicef_focal_points' ])) self.assertEqual(result['number'], str(self.intervention)) self.assertEqual(result['partner'], self.intervention.agreement.partner.name) self.assertEqual(result['start_date'], '2017-08-01') self.assertEqual( result['url'], 'https://{}/pmp/interventions/{}/details'.format( settings.HOST, self.intervention.id)) self.assertEqual(result['unicef_focal_points'], [self.focal_point_user.email])
def test_intervention_suspendable_statuses(self): """Interventions in amendment cannot be suspended""" suspendable_statuses = [Intervention.SIGNED, Intervention.ACTIVE] for suspendable_status in suspendable_statuses: intervention = InterventionFactory( status=suspendable_status, ) self.assertTrue(transition_to_suspended(intervention)) intervention.in_amendment = True with self.assertRaises(TransitionError): transition_to_suspended(intervention)
def test_intervention_terminable_statuses(self): """Interventions in amendment cannot be terminated""" terminable_statuses = [Intervention.SIGNED, Intervention.ACTIVE] for terminable_status in terminable_statuses: intervention = InterventionFactory(status=terminable_status, end=datetime.date.today()) a = AttachmentFactory(code='partners_intervention_termination_doc', content_object=intervention) intervention.termination_doc_attachment.add(a) self.assertTrue(transition_to_terminated(intervention)) intervention.in_amendment = True with self.assertRaises(TransitionError): transition_to_terminated(intervention)
def test_remap_in_use_validation_success(self): self.mock_sql.return_value = { "rows": [{ "old_pcode": self.remapped_location.p_code, "new_pcode": self.new_location.p_code }] } intervention = InterventionFactory(status=Intervention.SIGNED) intervention.flat_locations.add(self.remapped_location) intervention.save() response = self._run_validation(self.carto_table.pk) self.assertTrue(response)
def test_remap_in_use_cleanup(self): self.mock_sql.return_value = { "rows": [{ "old_pcode": self.remapped_location.p_code, "new_pcode": self.new_location.p_code }] } intervention = InterventionFactory(status=Intervention.SIGNED) intervention.flat_locations.add(self.remapped_location) intervention.save() self.assertEqual(len(Location.objects.all_locations()), 5) self._run_cleanup(self.carto_table.pk) self.assertEqual(len(Location.objects.all_locations()), 2)
def test_intervention_terminable_statuses(self): """Interventions in amendment cannot be terminated""" terminable_statuses = [Intervention.SIGNED, Intervention.ACTIVE] for terminable_status in terminable_statuses: intervention = InterventionFactory( status=terminable_status, end=datetime.date.today() ) a = AttachmentFactory(code='partners_intervention_termination_doc', content_object=intervention) intervention.termination_doc_attachment.add(a) self.assertTrue(transition_to_terminated(intervention)) intervention.in_amendment = True with self.assertRaises(TransitionError): transition_to_terminated(intervention)
def test_intervention_locations_in_use(self): # add intervention locations and test the response intervention = InterventionFactory(status=Intervention.SIGNED) intervention.flat_locations.add(self.location_no_geom, self.location_with_geom) intervention.save() response = self.forced_auth_req( "get", reverse("management_gis:locations-gis-in-use"), user=self.unicef_staff, data={"country_id": self.country.id, "geo_format": "whatever"}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(sorted(response.data[0].keys()), ["gateway_id", "id", "level", "name", "p_code", "parent_id"])
def setUp(self): super().setUp() self.agreement = AgreementFactory(agreement_type=Agreement.SSFA, ) self.intervention = InterventionFactory( document_type=Intervention.SSFA, agreement=self.agreement, )
def test_no_interventions(self): """If intervention does not fit in with Country Programmes then no issues raised """ qs_issue = FlaggedIssue.objects.filter(issue_id="pd_outputs_wrong") start_date = datetime.date(2001, 1, 1) end_date = datetime.date(2001, 12, 31) country = CountryProgrammeFactory( from_date=start_date, to_date=end_date, ) intervention = InterventionFactory( country_programme=country, start=start_date - datetime.timedelta(days=1), ) result = ResultFactory(country_programme=CountryProgrammeFactory()) InterventionResultLink.objects.create( intervention=intervention, cp_output=result, ) self.assertNotEqual(intervention.country_programme, result.country_programme) self.assertFalse(qs_issue.exists()) checks.bootstrap_checks(default_is_active=True) checks.run_all_checks() self.assertFalse(qs_issue.exists())
def setUpTestData(cls): cls.unicef_staff = UserFactory(is_staff=True) cls.intervention = InterventionFactory() cls.result_link = InterventionResultLinkFactory() cls.lower_result = LowerResultFactory( name="LL Name", result_link=cls.result_link, ) cls.indicator = IndicatorBlueprintFactory() AppliedIndicatorFactory( context_code="CC321", indicator=cls.indicator, lower_result=LowerResultFactory(name="LL Name", result_link=cls.result_link), cluster_name='ABC', ) AppliedIndicatorFactory( context_code="CC321", indicator=cls.indicator, lower_result=LowerResultFactory(name="LL Name", result_link=cls.result_link), cluster_name='XYZ', ) AppliedIndicatorFactory( context_code="CC321", indicator=cls.indicator, lower_result=LowerResultFactory(name="LL Name", result_link=cls.result_link), cluster_name='XYZ', ) AppliedIndicatorFactory( context_code="CC321", indicator=cls.indicator, lower_result=LowerResultFactory(name="LL Name", result_link=cls.result_link), ) cls.url = reverse("reports:cluster")
def test_no_issue(self): """Check that valida interventions results in no issue""" qs_issue = FlaggedIssue.objects.filter(issue_id="pd_outputs_wrong") start_date = datetime.date(2001, 1, 1) end_date = datetime.date(2001, 12, 31) country = CountryProgrammeFactory( from_date=start_date, to_date=end_date, ) intervention = InterventionFactory( country_programme=country, start=start_date, ) result = ResultFactory(country_programme=country) InterventionResultLink.objects.create( intervention=intervention, cp_output=result, ) self.assertEqual(intervention.country_programme, result.country_programme) self.assertFalse(qs_issue.exists()) checks.bootstrap_checks(default_is_active=True) checks.run_all_checks() self.assertFalse(qs_issue.exists())
def test_cp_previous(self): date_past = datetime.date.today() - datetime.timedelta(days=10) date_future = datetime.date.today() + datetime.timedelta(days=10) partner = PartnerFactory() cp_previous = CountryProgrammeFactory( from_date=date_past, to_date=datetime.date.today(), ) agreement_previous = AgreementFactory( partner=partner, agreement_type=Agreement.PCA, country_programme=cp_previous, ) cp = CountryProgrammeFactory( from_date=datetime.date.today() + datetime.timedelta(days=1), to_date=date_future, ) AgreementFactory( partner=partner, agreement_type=Agreement.PCA, country_programme=cp, ) InterventionFactory( document_type=Intervention.PD, start=date_past + datetime.timedelta(days=1), end=datetime.date.today() + datetime.timedelta(days=1), agreement=agreement_previous, ) mock_send = Mock() with patch(self.send_path, mock_send): utils.send_pca_missing_notifications() self.assertEqual(mock_send.call_count, 0)
def test_issue_found(self): """Check that is country programme for intervention does not match result country programme then issue is created""" qs_issue = FlaggedIssue.objects.filter(issue_id="pd_outputs_wrong") start_date = datetime.date(2001, 1, 1) end_date = datetime.date(2001, 12, 31) country = CountryProgrammeFactory( from_date=start_date, to_date=end_date, ) intervention = InterventionFactory( country_programme=country, start=start_date, ) result = ResultFactory(country_programme=CountryProgrammeFactory()) InterventionResultLink.objects.create( intervention=intervention, cp_output=result, ) self.assertNotEqual(intervention.country_programme, result.country_programme) self.assertFalse(qs_issue.exists()) checks.bootstrap_checks(default_is_active=True) checks.run_all_checks() self.assertTrue(qs_issue.exists()) issue = qs_issue.first() self.assertIn("has wrongly mapped outputs", issue.message)
def setUpTestData(cls): cls.file_type_partner = AttachmentFileTypeFactory( code="partners_partner_assessment") cls.file_type_agreement = AttachmentFileTypeFactory( code="partners_agreement") cls.file_type_assessment = AttachmentFileTypeFactory( code="partners_assessment_report") cls.file_type_agreement_amendment = AttachmentFileTypeFactory( code="partners_agreement_amendment") cls.file_type_intervention_prc_review = AttachmentFileTypeFactory( code="partners_intervention_prc_review") cls.file_type_intervention_signed_pd = AttachmentFileTypeFactory( code="partners_intervention_signed_pd") cls.file_type_intervention_amendment = AttachmentFileTypeFactory( code="partners_intervention_amendment_signed") cls.file_type_intervention_attachment = AttachmentFileTypeFactory( code="partners_intervention_attachment") cls.partner = PartnerFactory() cls.core_values_assessment = CoreValuesAssessmentFactory( assessment="sample.pdf") cls.agreement = AgreementFactory(attached_agreement="sample.pdf") cls.assessment = AssessmentFactory(report="sample.pdf") cls.agreement_amendment = AgreementAmendmentFactory( signed_amendment="sample.pdf") cls.intervention = InterventionFactory( prc_review_document="prc_sample.pdf", signed_pd_document="pd_sample.pdf") cls.intervention_amendment = InterventionAmendmentFactory( signed_amendment="sample.pdf") cls.intervention_attachment = InterventionAttachmentFactory( attachment="sample.pdf")
def setUpTestData(cls): cls.unicef_staff = UserFactory(is_staff=True) cls.partner = PartnerFactory( partner_type=PartnerType.UN_AGENCY, vendor_number='Vendor No', short_name="Short Name", alternate_name="Alternate Name", shared_with=["DPKO", "ECA"], address="Address 123", phone_number="Phone no 1234567", email="*****@*****.**", rating=PartnerOrganization.RATING_HIGH, core_values_assessment_date=datetime.date.today(), total_ct_cp=10000, total_ct_cy=20000, net_ct_cy=100.0, reported_cy=300.0, total_ct_ytd=400.0, deleted_flag=False, blocked=False, type_of_assessment="Type of Assessment", last_assessment_date=datetime.date.today(), ) cls.partnerstaff = PartnerStaffFactory(partner=cls.partner) attachment = tempfile.NamedTemporaryFile(suffix=".pdf").name cls.agreement = AgreementFactory( partner=cls.partner, country_programme=CountryProgrammeFactory(wbs="random WBS"), attached_agreement=attachment, start=datetime.date.today(), end=datetime.date.today(), signed_by_unicef_date=datetime.date.today(), signed_by=cls.unicef_staff, signed_by_partner_date=datetime.date.today()) cls.agreement.authorized_officers.add(cls.partnerstaff) cls.agreement.save() # This is here to test partner scoping AgreementFactory(signed_by_unicef_date=datetime.date.today()) cls.intervention = InterventionFactory( agreement=cls.agreement, document_type='SHPD', status='draft', start=datetime.date.today(), end=datetime.date.today(), submission_date=datetime.date.today(), submission_date_prc=datetime.date.today(), review_date_prc=datetime.date.today(), signed_by_unicef_date=datetime.date.today(), signed_by_partner_date=datetime.date.today(), unicef_signatory=cls.unicef_staff, population_focus="Population focus", partner_authorized_officer_signatory=cls.partnerstaff, country_programme=cls.agreement.country_programme, ) cls.ib = InterventionBudgetFactory(intervention=cls.intervention, currency="USD") cls.planned_visit = PartnerPlannedVisitsFactory(partner=cls.partner) output_res_type, _ = ResultType.objects.get_or_create(name='Output') cls.result = ResultFactory(result_type=output_res_type)
def test_send(self): intervention = InterventionFactory(status=Intervention.DRAFT) tz = timezone.get_default_timezone() intervention.created = datetime.datetime(2018, 1, 1, 12, 55, 12, 12345, tzinfo=tz) intervention.save() mock_send = Mock() with patch(self.send_path, mock_send): utils.send_intervention_draft_notification() self.assertEqual(mock_send.call_count, 1)
def test_ssfa_invalid(self): """If document type SSFA, and agreement type is SSFA invalid if agreement interventions count is > 1 """ InterventionFactory(agreement=self.agreement) self.assertFalse( ssfa_agreement_has_no_other_intervention(self.intervention))
def test_prp_api_performance(self): EXPECTED_QUERIES = 24 with self.assertNumQueries(EXPECTED_QUERIES): self.run_prp_v1(user=self.unicef_staff, method='get') # make a bunch more stuff, make sure queries don't go up. intervention = InterventionFactory(agreement=self.agreement, title='New Intervention') result = ResultFactory(name='Another Result') result_link = InterventionResultLink.objects.create( intervention=intervention, cp_output=result) lower_result = LowerResult.objects.create(result_link=result_link, name='Lower Result 1') indicator_blueprint = IndicatorBlueprint.objects.create( title='The Blueprint') applied_indicator = AppliedIndicator.objects.create( indicator=indicator_blueprint, lower_result=lower_result, ) applied_indicator.locations.add( LocationFactory(name='A Location', gateway=GatewayTypeFactory(name='Another Gateway'), p_code='a-p-code')) applied_indicator.disaggregation.create(name='Another Disaggregation') with self.assertNumQueries(EXPECTED_QUERIES): self.run_prp_v1(user=self.unicef_staff, method='get')
def setUp(self): super(TestSSFAgreementHasNoOtherIntervention, self).setUp() self.agreement = AgreementFactory(agreement_type=Agreement.SSFA, ) self.intervention = InterventionFactory( document_type=Intervention.SSFA, agreement=self.agreement, )
def test_intervention(self): intervention = InterventionFactory() fields = utils.get_to_many_field_names(intervention.__class__) # check many_to_one field self.assertIn("frs", fields) # check many_to_many field self.assertIn("sections", fields)
def setUpTestData(cls): cls.code_1 = "test_code_1" cls.file_type_1 = AttachmentFileTypeFactory(code=cls.code_1) cls.code_2 = "test_code_2" cls.file_type_2 = AttachmentFileTypeFactory(code=cls.code_2) cls.unicef_staff = UserFactory(is_staff=True) cls.user = UserFactory() cls.url = reverse("attachments:list") cls.attachment_1 = AttachmentFactory( file_type=cls.file_type_1, code=cls.code_1, file="sample1.pdf", content_object=cls.file_type_1, uploaded_by=cls.unicef_staff ) cls.attachment_2 = AttachmentFactory( file_type=cls.file_type_2, code=cls.code_2, file="sample2.pdf", content_object=cls.file_type_2, uploaded_by=cls.user ) cls.partner = PartnerFactory( partner_type=PartnerType.UN_AGENCY, vendor_number="V123", ) cls.agreement = AgreementFactory(partner=cls.partner) cls.assessment = AssessmentFactory(partner=cls.partner) cls.amendment = AgreementAmendmentFactory(agreement=cls.agreement) cls.intervention = InterventionFactory(agreement=cls.agreement) cls.result_link = InterventionResultLinkFactory( intervention=cls.intervention ) cls.intervention_amendment = InterventionAmendmentFactory( intervention=cls.intervention ) cls.intervention_attachment = InterventionAttachmentFactory( intervention=cls.intervention ) cls.tpm_partner = SimpleTPMPartnerFactory(vendor_number="V432") cls.tpm_visit = TPMVisitFactory(tpm_partner=cls.tpm_partner) cls.tpm_activity = TPMActivityFactory( partner=cls.partner, intervention=cls.intervention, tpm_visit=cls.tpm_visit ) cls.engagement = EngagementFactory(partner=cls.partner) cls.default_partner_response = [{ "partner": "", "partner_type": "", "vendor_number": "", "pd_ssfa_number": "", "agreement_reference_number": "", "source": "", }] * 2
def test_end_after_today(self): """End date cannot be after today's date'""" intervention = InterventionFactory(end=datetime.date.today() + datetime.timedelta(days=2)) with self.assertRaisesRegexp(TransitionError, "End date is in the future"): transition_to_closed(intervention) self.assertFundamentals(intervention.total_frs)
def test_start_date_after_signed_date(self): """Start date after max signed date is valid""" intervention = InterventionFactory( signed_by_unicef_date=datetime.date(2001, 2, 1), signed_by_partner_date=datetime.date(2001, 3, 1), signed_pd_document="random.pdf", start=datetime.date(2001, 4, 1)) self.assertTrue(start_date_signed_valid(intervention))
def test_command(self): send_path = "etools.applications.partners.utils.send_notification_with_template" intervention = InterventionFactory(status=Intervention.DRAFT) tz = timezone.get_default_timezone() intervention.created = datetime.datetime(2018, 1, 1, 12, 55, 12, 12345, tzinfo=tz) intervention.save() mock_send = Mock() with patch(send_path, mock_send): call_command("send_intervention_draft_notification") self.assertEqual(mock_send.call_count, 1)
def setUp(self): super(TestAmendmentsInvalid, self).setUp() self.intervention = InterventionFactory(status=Intervention.DRAFT, ) self.intervention.old_instance = self.intervention self.amendment = InterventionAmendmentFactory( intervention=self.intervention, signed_date=datetime.date(2001, 1, 1), signed_amendment="random.pdf", )
def test_create(self): user = UserFactory() intervention = InterventionFactory() activity = utils.create_snapshot(intervention, {}, user) self.assertEqual(activity.target, intervention) self.assertEqual(activity.action, activity.CREATE) self.assertEqual(activity.by_user, user) self.assertEqual(activity.data["title"], intervention.title) self.assertEqual(activity.change, {})
def test_send_not_draft(self): intervention = InterventionFactory(status=Intervention.SIGNED) self.assertTrue(intervention.status != Intervention.DRAFT) self.assertFalse( Intervention.objects.filter(status=Intervention.DRAFT).exists()) mock_send = Mock() with patch(self.send_path, mock_send): utils.send_intervention_draft_notification() self.assertEqual(mock_send.call_count, 0)
def setUpTestData(cls): cls.unicef_staff = UserFactory(is_staff=True) group = GroupFactory(name='Partnership Manager') cls.unicef_staff.groups.add(group) cls.intervention = InterventionFactory( start=datetime.date(2001, 1, 1), status=Intervention.DRAFT, in_amendment=True, )
def test_send_has_no_frs(self): InterventionFactory( status=Intervention.SIGNED, start=datetime.date.today() - datetime.timedelta(days=2), ) mock_send = Mock() with patch(self.send_path, mock_send): utils.send_intervention_past_start_notification() self.assertEqual(mock_send.call_count, 0)
def test_save_model_update(self): self.assertFalse(Activity.objects.exists()) ia = InterventionAdmin(Intervention, self.site) obj = InterventionFactory() title_before = obj.title obj.title = "Title Change" ia.save_model(self.request, obj, {}, True) self.assertTrue( Activity.objects.filter(action=Activity.UPDATE).exists() ) activity = Activity.objects.first() self.assertEqual(activity.target, obj) self.assertEqual(activity.by_user, self.user) self.assertDictEqual(activity.change, { "title": { "before": title_before, "after": "Title Change" } })
def test_update_intervention(self): """Ensure agreement update fails if intervention dates aren't appropriate. I don't think it's possible to supply interventions when creating via the serializer, so this only tests update. """ agreement = AgreementFactory(agreement_type=Agreement.SSFA, partner=self.partner, status=Agreement.DRAFT, start=self.today - datetime.timedelta(days=5), end=self.today + datetime.timedelta(days=5), signed_by_unicef_date=None, signed_by_partner_date=None, reference_number_year=datetime.date.today().year) intervention = InterventionFactory(agreement=agreement) # Start w/an invalid intervention. data = { "agreement": agreement, "intervention": intervention, } serializer = AgreementCreateUpdateSerializer() # If I don't set serializer.instance, the validator gets confused. I guess (?) this is ordinarily set by DRF # during an update? serializer.instance = agreement serializer.context['request'] = self.fake_request with self.assertRaises(serializers.ValidationError) as context_manager: serializer.validate(data=data) self.assertSimpleExceptionFundamentals( context_manager, "Start and end dates don't match the Document's start and end" ) # Set start date and save again; it should still fail because end date isn't set. intervention.start = agreement.start intervention.save() with self.assertRaises(serializers.ValidationError) as context_manager: serializer.validate(data=data) self.assertSimpleExceptionFundamentals( context_manager, "Start and end dates don't match the Document's start and end" ) # Set start date and save again; it should still fail because end date doesn't match agreement end date. intervention.end = agreement.end + datetime.timedelta(days=100) intervention.save() with self.assertRaises(serializers.ValidationError) as context_manager: serializer.validate(data=data) self.assertSimpleExceptionFundamentals( context_manager, "Start and end dates don't match the Document's start and end" ) # Set start date and save again; it should now succeed. intervention.end = agreement.end intervention.save() # Should not raise an exception serializer.validate(data=data)