Skip to content

Commit

Permalink
Refactor tests
Browse files Browse the repository at this point in the history
Now that two criteria can be certified, having
`GEIQEligibilityDiagnosisFactory.with_certifiable_criteria` choose
randomly from a list of criteria would be unpredictable and could
cause flaky tests.
Better use parametrized tests.
  • Loading branch information
celine-m-s committed Feb 3, 2025
1 parent a076562 commit 7dc5dea
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 228 deletions.
66 changes: 38 additions & 28 deletions tests/eligibility/factories.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import datetime
import random

import factory
from dateutil.relativedelta import relativedelta
Expand All @@ -8,19 +7,15 @@

from itou.companies.enums import CompanyKind
from itou.eligibility import models
from itou.eligibility.enums import AdministrativeCriteriaAnnex, AuthorKind
from itou.eligibility.enums import AuthorKind
from itou.eligibility.models.common import AbstractEligibilityDiagnosisModel
from itou.eligibility.models.geiq import GEIQAdministrativeCriteria
from itou.eligibility.models.iae import AdministrativeCriteria
from tests.companies.factories import CompanyFactory, CompanyWith2MembershipsFactory
from tests.prescribers.factories import PrescriberOrganizationWithMembershipFactory
from tests.users.factories import JobSeekerFactory


def _add_administrative_criteria(self, create, extracted, qs, **kwargs):
# Pick random results.
criteria = qs.order_by("?")[: random.randint(2, 5)]
self.administrative_criteria.add(*criteria)


faker = Faker()


Expand Down Expand Up @@ -51,16 +46,11 @@ class Params:
job_seeker = factory.SubFactory(JobSeekerFactory)


def _get_geiq_certifiable_criteria(self, create, extracted, **kwargs):
qs = models.GEIQAdministrativeCriteria.objects.exclude(annex=AdministrativeCriteriaAnnex.NO_ANNEX).certifiable()
_add_administrative_criteria(self, create, extracted, qs, **kwargs)


def _get_geiq_not_certifiable_criteria(self, create, extracted, **kwargs):
qs = models.GEIQAdministrativeCriteria.objects.exclude(
annex=AdministrativeCriteriaAnnex.NO_ANNEX
).not_certifiable()
_add_administrative_criteria(self, create, extracted, qs, **kwargs)
def _add_geiq_administrative_criteria_with_kind(self, create, extracted, **kwargs):
if "criteria_kind" in kwargs.keys():
criteria_kind = kwargs.pop("criteria_kind")
admin_criterion = GEIQAdministrativeCriteria.objects.get(kind=criteria_kind)
self.administrative_criteria.add(admin_criterion)


class GEIQEligibilityDiagnosisFactory(AbstractEligibilityDiagnosisModelFactory):
Expand All @@ -78,18 +68,24 @@ class Params:
author_geiq=factory.SubFactory(CompanyWith2MembershipsFactory, kind=CompanyKind.GEIQ, with_jobs=True),
author=factory.LazyAttribute(lambda obj: obj.author_geiq.members.first()),
)
with_certifiable_criteria = factory.Trait(romes=factory.PostGeneration(_get_geiq_certifiable_criteria))
with_not_certifiable_criteria = factory.Trait(romes=factory.PostGeneration(_get_geiq_not_certifiable_criteria))
with_criteria_kind = factory.PostGeneration(_add_geiq_administrative_criteria_with_kind)


def _get_iae_certifiable_criteria(self, create, extracted, **kwargs):
qs = models.AdministrativeCriteria.objects.certifiable()
_add_administrative_criteria(self, create, extracted, qs, **kwargs)
def geiq_eligibility_with_criteria_factory(criteria_kind):
return GEIQEligibilityDiagnosisFactory(
job_seeker__with_address=True,
job_seeker__born_in_france=True,
from_geiq=True,
with_criteria_kind=True,
with_criteria_kind__criteria_kind=criteria_kind,
)


def _get_iae_not_certifiable_criteria(self, create, extracted, **kwargs):
qs = models.AdministrativeCriteria.objects.not_certifiable()
_add_administrative_criteria(self, create, extracted, qs, **kwargs)
def _add_iae_administrative_criteria_with_kind(self, create, extracted, **kwargs):
if "criteria_kind" in kwargs.keys():
criteria_kind = kwargs.pop("criteria_kind")
admin_criterion = AdministrativeCriteria.objects.get(kind=criteria_kind)
self.administrative_criteria.add(admin_criterion)


class IAEEligibilityDiagnosisFactory(AbstractEligibilityDiagnosisModelFactory):
Expand All @@ -106,5 +102,19 @@ class Params:
author_prescriber_organization=None,
author=factory.LazyAttribute(lambda obj: obj.author_siae.members.first()),
)
with_certifiable_criteria = factory.Trait(romes=factory.PostGeneration(_get_iae_certifiable_criteria))
with_not_certifiable_criteria = factory.Trait(romes=factory.PostGeneration(_get_iae_not_certifiable_criteria))
with_criteria_kind = factory.PostGeneration(_add_iae_administrative_criteria_with_kind)


def iae_eligibility_with_criteria_factory(criteria_kind):
return IAEEligibilityDiagnosisFactory(
job_seeker__with_address=True,
job_seeker__born_in_france=True,
from_employer=True,
with_criteria_kind=True,
with_criteria_kind__criteria_kind=criteria_kind,
)


# TODO: add a not certifiable factory?
# looking for:
# with_criteria_kind__criteria_kind=AdministrativeCriteriaKind.CAP_BEP
24 changes: 16 additions & 8 deletions tests/eligibility/test_geiq.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.db.models import Max

from itou.companies.enums import CompanyKind
from itou.eligibility.enums import AdministrativeCriteriaAnnex, AdministrativeCriteriaLevel
from itou.eligibility.enums import AdministrativeCriteriaAnnex, AdministrativeCriteriaKind, AdministrativeCriteriaLevel
from itou.eligibility.models import GEIQAdministrativeCriteria, GEIQEligibilityDiagnosis
from itou.gps.models import FollowUpGroup, FollowUpGroupMembership
from tests.companies.factories import CompanyWithMembershipAndJobsFactory
Expand Down Expand Up @@ -456,24 +456,32 @@ def test_administrativecriteria_level_annex_consistency():


@pytest.mark.parametrize(
"factory_params,expected",
"factory_params,CRITERIA_KIND,expected",
[
pytest.param(
{"from_prescriber": True, "with_certifiable_criteria": True}, False, id="prescriber_certified_criteria"
{"from_prescriber": True}, AdministrativeCriteriaKind.RSA, False, id="prescriber_certified_criteria"
),
pytest.param(
{"from_prescriber": True, "with_not_certifiable_criteria": True},
{"from_prescriber": True},
AdministrativeCriteriaKind.CAP_BEP,
False,
id="prescriber_no_certified_criteria",
),
pytest.param(
{"from_geiq": True, "with_not_certifiable_criteria": True},
{"from_geiq": True},
AdministrativeCriteriaKind.CAP_BEP,
False,
id="employer_no_certified_criteria",
),
pytest.param({"from_geiq": True, "with_certifiable_criteria": True}, True, id="employer_certified_criteria"),
pytest.param({"from_geiq": True}, AdministrativeCriteriaKind.RSA, True, id="employer_certified_criteria"),
],
)
def test_criteria_can_be_certified(factory_params, expected):
diagnosis = GEIQEligibilityDiagnosisFactory(**factory_params)
def test_criteria_can_be_certified(factory_params, CRITERIA_KIND, expected):
diagnosis = GEIQEligibilityDiagnosisFactory(
job_seeker__with_address=True,
job_seeker__born_in_france=True,
with_criteria_kind=True,
with_criteria_kind__criteria_kind=CRITERIA_KIND,
**factory_params,
)
assert diagnosis.criteria_can_be_certified() == expected
84 changes: 54 additions & 30 deletions tests/eligibility/test_iae.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
from tests.eligibility.factories import (
GEIQEligibilityDiagnosisFactory,
IAEEligibilityDiagnosisFactory,
geiq_eligibility_with_criteria_factory,
iae_eligibility_with_criteria_factory,
)
from tests.job_applications.factories import JobApplicationFactory
from tests.prescribers.factories import PrescriberOrganizationWithMembershipFactory
Expand Down Expand Up @@ -439,28 +441,36 @@ def test_is_considered_valid(self):
assert diagnosis.is_considered_valid

@pytest.mark.parametrize(
"factory_params,expected",
"factory_params,CRITERIA_KIND,expected",
[
pytest.param(
{"from_prescriber": True, "with_certifiable_criteria": True}, False, id="prescriber_certified_criteria"
{"from_prescriber": True}, AdministrativeCriteriaKind.RSA, False, id="prescriber_certified_criteria"
),
pytest.param(
{"from_prescriber": True, "with_not_certifiable_criteria": True},
{"from_prescriber": True},
AdministrativeCriteriaKind.CAP_BEP,
False,
id="prescriber_no_certified_criteria",
),
pytest.param(
{"from_employer": True, "with_not_certifiable_criteria": True},
{"from_employer": True},
AdministrativeCriteriaKind.CAP_BEP,
False,
id="employer_no_certified_criteria",
),
pytest.param(
{"from_employer": True, "with_certifiable_criteria": True}, True, id="employer_certified_criteria"
{"from_employer": True}, AdministrativeCriteriaKind.RSA, True, id="employer_certified_criteria"
),
],
)
def test_criteria_can_be_certified(self, factory_params, expected):
diagnosis = IAEEligibilityDiagnosisFactory(**factory_params)
def test_criteria_can_be_certified(self, factory_params, CRITERIA_KIND, expected):
diagnosis = IAEEligibilityDiagnosisFactory(
job_seeker__with_address=True,
job_seeker__born_in_france=True,
with_criteria_kind=True,
with_criteria_kind__criteria_kind=CRITERIA_KIND,
**factory_params,
)
assert diagnosis.criteria_can_be_certified() == expected


Expand Down Expand Up @@ -602,33 +612,37 @@ def test_eligibility_diagnosis_certify_criteria(


@pytest.mark.parametrize(
"EligibilityDiagnosisFactory",
"eligibility_diagnosis_factory",
[
pytest.param(
partial(IAEEligibilityDiagnosisFactory, from_employer=True),
id="test_selected_administrative_criteria_certify_iae",
),
pytest.param(
partial(GEIQEligibilityDiagnosisFactory, from_geiq=True),
id="test_selected_administrative_criteria_certify_geiq",
),
iae_eligibility_with_criteria_factory,
geiq_eligibility_with_criteria_factory,
],
)
@pytest.mark.parametrize(
"CRITERIA_KIND",
[
AdministrativeCriteriaKind.RSA,
AdministrativeCriteriaKind.AAH,
],
)
def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, EligibilityDiagnosisFactory):
def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, CRITERIA_KIND, eligibility_diagnosis_factory):
RSA_ENDPOINT = f"{settings.API_PARTICULIER_BASE_URL}v2/revenu-solidarite-active"
respx_mock.get(RSA_ENDPOINT).mock(side_effect=Exception)
job_seeker = JobSeekerFactory() # Missing data.
eligibility_diagnosis = EligibilityDiagnosisFactory(with_certifiable_criteria=True, job_seeker=job_seeker)
eligibility_diagnosis = eligibility_diagnosis_factory(
criteria_kind=CRITERIA_KIND,
)
eligibility_diagnosis.job_seeker = job_seeker
eligibility_diagnosis.certify_criteria()
assert len(respx_mock.calls) == 0


@freeze_time("2024-09-12T00:00:00Z")
@pytest.mark.parametrize(
"EligibilityDiagnosisFactory,expected,response_status,response",
"eligibility_diagnosis_factory,expected,response_status,response",
[
pytest.param(
partial(IAEEligibilityDiagnosisFactory, from_employer=True),
iae_eligibility_with_criteria_factory,
{
"certification_period": InclusiveDateRange(datetime.date(2024, 8, 1), datetime.date(2024, 12, 13)),
"certified": True,
Expand All @@ -640,7 +654,7 @@ def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, Eligibi
id="iae-certified",
),
pytest.param(
partial(GEIQEligibilityDiagnosisFactory, from_geiq=True),
geiq_eligibility_with_criteria_factory,
{
"certification_period": InclusiveDateRange(datetime.date(2024, 8, 1), datetime.date(2024, 12, 13)),
"certified": True,
Expand All @@ -652,7 +666,7 @@ def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, Eligibi
id="geiq-certified",
),
pytest.param(
partial(IAEEligibilityDiagnosisFactory, from_employer=True),
iae_eligibility_with_criteria_factory,
{
"certification_period": None,
"certified": False,
Expand All @@ -664,7 +678,7 @@ def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, Eligibi
id="iae-not-certified",
),
pytest.param(
partial(GEIQEligibilityDiagnosisFactory, from_geiq=True),
geiq_eligibility_with_criteria_factory,
{
"certification_period": None,
"certified": False,
Expand All @@ -676,7 +690,7 @@ def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, Eligibi
id="geiq-not-certified",
),
pytest.param(
partial(IAEEligibilityDiagnosisFactory, from_employer=True),
iae_eligibility_with_criteria_factory,
{
"certification_period": None,
"certified": None,
Expand All @@ -688,7 +702,7 @@ def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, Eligibi
id="iae-not-found",
),
pytest.param(
partial(GEIQEligibilityDiagnosisFactory, from_geiq=True),
geiq_eligibility_with_criteria_factory,
{
"certification_period": None,
"certified": None,
Expand All @@ -702,10 +716,9 @@ def test_eligibility_diagnosis_certify_criteria_missing_info(respx_mock, Eligibi
],
)
def test_selected_administrative_criteria_certified(
expected, response, response_status, respx_mock, EligibilityDiagnosisFactory
expected, response, response_status, respx_mock, eligibility_diagnosis_factory
):
job_seeker = JobSeekerFactory(with_address=True, born_in_france=True)
eligibility_diagnosis = EligibilityDiagnosisFactory(with_certifiable_criteria=True, job_seeker=job_seeker)
eligibility_diagnosis = eligibility_diagnosis_factory(criteria_kind=AdministrativeCriteriaKind.RSA)
respx_mock.get(f"{settings.API_PARTICULIER_BASE_URL}v2/revenu-solidarite-active").respond(
response_status, json=response
)
Expand All @@ -722,7 +735,14 @@ def test_selected_administrative_criteria_certified(
assert len(respx_mock.calls) == 1


def test_with_is_considered_certified():
@pytest.mark.parametrize(
"CRITERIA_KIND",
[
AdministrativeCriteriaKind.RSA,
AdministrativeCriteriaKind.AAH,
],
)
def test_with_is_considered_certified(CRITERIA_KIND):
def assert_considered_valid_count(hiring_start_at, expected):
assert (
diagnosis.selected_administrative_criteria.with_is_considered_certified(hiring_start_at)
Expand All @@ -731,7 +751,11 @@ def assert_considered_valid_count(hiring_start_at, expected):
== expected
)

diagnosis = IAEEligibilityDiagnosisFactory(with_certifiable_criteria=True, from_employer=True)
# 2 selected criteria in total.
diagnosis = iae_eligibility_with_criteria_factory(criteria_kind=CRITERIA_KIND)
admin_criterion = AdministrativeCriteria.objects.get(kind=CRITERIA_KIND)
diagnosis.administrative_criteria.add(admin_criterion)

for selected_criterion in diagnosis.selected_administrative_criteria.all():
selected_criterion.certified = True
certification_period_start = timezone.now() - datetime.timedelta(days=10)
Expand Down
28 changes: 3 additions & 25 deletions tests/eligibility/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,17 @@
from huey.exceptions import RetryTask

from itou.eligibility.enums import AdministrativeCriteriaKind
from itou.eligibility.models.geiq import GEIQAdministrativeCriteria
from itou.eligibility.models.iae import AdministrativeCriteria
from itou.eligibility.tasks import async_certify_criteria
from itou.utils.mocks.api_particulier import aah_certified_mocker, rsa_certified_mocker
from itou.utils.types import InclusiveDateRange
from tests.eligibility.factories import GEIQEligibilityDiagnosisFactory, IAEEligibilityDiagnosisFactory
from tests.users.factories import JobSeekerFactory


def create(factory, **kwargs):
job_seeker = JobSeekerFactory(with_address=True, born_in_france=True)
return factory(job_seeker=job_seeker, **kwargs)


def iae_eligibility_factory(criteria_kind):
diag = create(IAEEligibilityDiagnosisFactory, from_employer=True)
admin_criterion = AdministrativeCriteria.objects.get(kind=criteria_kind)
diag.administrative_criteria.add(admin_criterion)
return diag


def geiq_eligibility_factory(criteria_kind):
diag = create(GEIQEligibilityDiagnosisFactory, from_geiq=True)
admin_criterion = GEIQAdministrativeCriteria.objects.get(kind=criteria_kind)
diag.administrative_criteria.add(admin_criterion)
return diag
from tests.eligibility.factories import geiq_eligibility_with_criteria_factory, iae_eligibility_with_criteria_factory


@pytest.mark.parametrize(
"factory",
[
pytest.param(iae_eligibility_factory, id="iae"),
pytest.param(geiq_eligibility_factory, id="geiq"),
pytest.param(iae_eligibility_with_criteria_factory, id="iae"),
pytest.param(geiq_eligibility_with_criteria_factory, id="geiq"),
],
)
class TestCertifyCriteria:
Expand Down
Loading

0 comments on commit 7dc5dea

Please sign in to comment.