@@ -571,3 +571,110 @@ async def test_b():
571571 """ ))
572572 result = pytester .runpytest ("--asyncio-mode=strict" )
573573 result .assert_outcomes (passed = 2 )
574+
575+
576+ def test_sync_fixture_sees_same_loop_as_async_test_under_custom_factory (
577+ pytester : Pytester ,
578+ ) -> None :
579+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
580+ pytester .makeconftest (dedent ("""\
581+ import asyncio
582+
583+ class CustomEventLoop(asyncio.SelectorEventLoop):
584+ pass
585+
586+ def pytest_asyncio_loop_factories(config, item):
587+ return {"custom": CustomEventLoop}
588+ """ ))
589+ pytester .makepyfile (dedent ("""\
590+ import asyncio
591+ import pytest
592+ import pytest_asyncio
593+
594+ pytest_plugins = "pytest_asyncio"
595+
596+ @pytest_asyncio.fixture(autouse=True)
597+ def enable_debug_on_event_loop():
598+ asyncio.get_event_loop().set_debug(True)
599+
600+ @pytest.mark.asyncio
601+ async def test_debug_mode_visible():
602+ assert asyncio.get_running_loop().get_debug()
603+ """ ))
604+ result = pytester .runpytest ("--asyncio-mode=strict" )
605+ result .assert_outcomes (passed = 1 )
606+
607+
608+ @pytest .mark .parametrize ("loop_scope" , ("module" , "package" , "session" ))
609+ def test_async_generator_fixture_teardown_runs_under_custom_factory (
610+ pytester : Pytester ,
611+ loop_scope : str ,
612+ ) -> None :
613+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
614+ pytester .makeconftest (dedent (f"""\
615+ import asyncio
616+ import pytest_asyncio
617+
618+ class CustomEventLoop(asyncio.SelectorEventLoop):
619+ pass
620+
621+ def pytest_asyncio_loop_factories(config, item):
622+ return {{"custom": CustomEventLoop}}
623+
624+ @pytest_asyncio.fixture(
625+ autouse=True, scope="{ loop_scope } ", loop_scope="{ loop_scope } "
626+ )
627+ async def fixture_with_teardown():
628+ yield
629+ print("TEARDOWN_EXECUTED")
630+ """ ))
631+ pytester .makepyfile (dedent (f"""\
632+ import pytest
633+
634+ pytest_plugins = "pytest_asyncio"
635+
636+ @pytest.mark.asyncio(loop_scope="{ loop_scope } ")
637+ async def test_passes():
638+ assert True
639+ """ ))
640+ result = pytester .runpytest ("--asyncio-mode=strict" , "-s" )
641+ result .assert_outcomes (passed = 1 )
642+ result .stdout .fnmatch_lines (["*TEARDOWN_EXECUTED*" ])
643+
644+
645+ @pytest .mark .parametrize ("loop_scope" , ("module" , "package" , "session" ))
646+ def test_async_fixture_recreated_per_loop_factory_variant (
647+ pytester : Pytester ,
648+ loop_scope : str ,
649+ ) -> None :
650+ pytester .makeini ("[pytest]\n asyncio_default_fixture_loop_scope = function" )
651+ pytester .makeconftest (dedent (f"""\
652+ import asyncio
653+ import pytest_asyncio
654+
655+ class CustomLoopA(asyncio.SelectorEventLoop):
656+ pass
657+
658+ class CustomLoopB(asyncio.SelectorEventLoop):
659+ pass
660+
661+ def pytest_asyncio_loop_factories(config, item):
662+ return {{"loop_a": CustomLoopA, "loop_b": CustomLoopB}}
663+
664+ @pytest_asyncio.fixture(scope="{ loop_scope } ", loop_scope="{ loop_scope } ")
665+ async def fixture_loop_type():
666+ return type(asyncio.get_running_loop()).__name__
667+ """ ))
668+ pytester .makepyfile (dedent (f"""\
669+ import asyncio
670+ import pytest
671+
672+ pytest_plugins = "pytest_asyncio"
673+
674+ @pytest.mark.asyncio(loop_scope="{ loop_scope } ")
675+ async def test_fixture_matches_running_loop(fixture_loop_type):
676+ running_loop_type = type(asyncio.get_running_loop()).__name__
677+ assert fixture_loop_type == running_loop_type
678+ """ ))
679+ result = pytester .runpytest ("--asyncio-mode=strict" , "-v" )
680+ result .assert_outcomes (passed = 2 )
0 commit comments