33Achieves actual line coverage of src/backend/app.py by importing and executing the real module.
44Modified to work with pytest from root directory.
55
6- NOTE: These tests use sys.modules mocking which has platform-specific behavior.
7- They work on Windows but fail on Linux CI/CD with "TypeError: issubclass() arg 2 must be a class".
8- This is a known issue with Mock objects and FastAPI's type validation on Linux.
9- For proper cross-platform testing, use FastAPI's TestClient instead (see test_app_fixed.py).
6+ Uses MagicMock for proper cross-platform compatibility.
107"""
118
129import pytest
2522if src_path not in sys .path :
2623 sys .path .insert (0 , src_path )
2724
28- # Skip these tests on non-Windows platforms due to Mock/FastAPI compatibility issues
29- skip_on_linux = pytest .mark .skipif (
30- platform .system () != 'Windows' ,
31- reason = "sys.modules mocking causes issubclass() issues with FastAPI on Linux"
32- )
33-
3425
3526class MockUserLanguage (BaseModel ):
3627 """Mock UserLanguage model for testing."""
@@ -53,7 +44,6 @@ def create_router_mock():
5344 return mock_router
5445
5546
56- @skip_on_linux
5747def test_app_module_import ():
5848 """Test that the backend.app module can be imported successfully."""
5949 # Clean up any previous imports
@@ -120,7 +110,6 @@ def test_app_module_import():
120110 assert app_module .app is not None
121111
122112
123- @skip_on_linux
124113def test_user_browser_language_endpoint_real ():
125114 """Test the real user_browser_language_endpoint function."""
126115 # Mock dependencies with full module paths
@@ -164,7 +153,6 @@ def test_user_browser_language_endpoint_real():
164153 mock_config .set_user_local_browser_language .assert_called_once_with ('es-ES' )
165154
166155
167- @skip_on_linux
168156def test_user_browser_language_different_languages ():
169157 """Test user language endpoint with different Accept-Language headers."""
170158 mock_modules = {
@@ -208,7 +196,6 @@ def test_user_browser_language_different_languages():
208196 assert result == {"message" : "Language set successfully" }
209197
210198
211- @skip_on_linux
212199def test_user_browser_language_missing_header ():
213200 """Test user language endpoint with missing Accept-Language header."""
214201 mock_modules = {
@@ -247,7 +234,6 @@ def test_user_browser_language_missing_header():
247234 assert result == {"message" : "Language set successfully" }
248235
249236
250- @skip_on_linux
251237@pytest .mark .asyncio
252238async def test_lifespan_function ():
253239 """Test the lifespan function executes without errors."""
@@ -290,7 +276,6 @@ async def test_lifespan_function():
290276 assert True
291277
292278
293- @skip_on_linux
294279def test_fastapi_app_configuration ():
295280 """Test that the FastAPI app is configured correctly."""
296281 mock_modules = {
@@ -324,7 +309,6 @@ def test_fastapi_app_configuration():
324309 assert isinstance (app .app , FastAPI )
325310
326311
327- @skip_on_linux
328312def test_azure_monitor_configuration ():
329313 """Test Azure Monitor configuration is called."""
330314 mock_modules = {
@@ -364,7 +348,6 @@ def test_azure_monitor_configuration():
364348 pytest .main ([__file__ ])
365349
366350
367- @skip_on_linux
368351@pytest .mark .asyncio
369352async def test_user_browser_language_endpoint_real ():
370353 """Test the real user_browser_language_endpoint function."""
@@ -404,7 +387,6 @@ async def test_user_browser_language_endpoint_real():
404387 mock_config .set_user_local_browser_language .assert_called_once_with ('es-ES' )
405388
406389
407- @skip_on_linux
408390@pytest .mark .asyncio
409391async def test_user_browser_language_different_languages ():
410392 """Test user language endpoint with different Accept-Language headers."""
@@ -442,7 +424,6 @@ async def test_user_browser_language_different_languages():
442424 assert result == {"status" : "Language received successfully" }
443425
444426
445- @skip_on_linux
446427@pytest .mark .asyncio
447428async def test_user_browser_language_missing_header ():
448429 """Test user language endpoint with missing Accept-Language header."""
@@ -474,7 +455,6 @@ async def test_user_browser_language_missing_header():
474455 assert result == {"status" : "Language received successfully" }
475456
476457
477- @skip_on_linux
478458@pytest .mark .asyncio
479459async def test_lifespan_function ():
480460 """Test the lifespan function executes without errors."""
@@ -508,7 +488,6 @@ async def test_lifespan_function():
508488 assert True
509489
510490
511- @skip_on_linux
512491def test_fastapi_app_configuration ():
513492 """Test that the FastAPI app is configured correctly."""
514493 mock_modules = {
@@ -534,7 +513,6 @@ def test_fastapi_app_configuration():
534513 assert isinstance (app .app , FastAPI )
535514
536515
537- @skip_on_linux
538516def test_logger_exists ():
539517 """Test that logger is created."""
540518 mock_modules = {
@@ -564,7 +542,6 @@ def test_logger_exists():
564542 assert logger .level >= 0 # Should be a valid log level
565543
566544
567- @skip_on_linux
568545def test_azure_monitor_configuration ():
569546 """Test Azure Monitor configuration is called."""
570547 mock_modules = {
@@ -597,7 +574,6 @@ def test_azure_monitor_configuration():
597574class TestUserBrowserLanguageEndpoint :
598575 """Test the user browser language endpoint functionality."""
599576
600- @skip_on_linux
601577 def test_user_browser_language_endpoint_basic (self ):
602578 """Test the user_browser_language_endpoint function with basic language."""
603579 # Mock the configuration
@@ -622,7 +598,6 @@ def user_browser_language_endpoint(request):
622598 mock_config .set_user_local_browser_language .assert_called_once_with ('en-US' )
623599 assert result == {"message" : "Language set successfully" }
624600
625- @skip_on_linux
626601 def test_user_browser_language_endpoint_complex (self ):
627602 """Test with complex Accept-Language header."""
628603 mock_config = Mock ()
@@ -642,7 +617,6 @@ def user_browser_language_endpoint(request):
642617 mock_config .set_user_local_browser_language .assert_called_once_with ('fr-FR' )
643618 assert result == {"message" : "Language set successfully" }
644619
645- @skip_on_linux
646620 def test_user_browser_language_endpoint_missing_header (self ):
647621 """Test with missing Accept-Language header."""
648622 mock_config = Mock ()
@@ -667,7 +641,6 @@ def user_browser_language_endpoint(request):
667641class TestLifespanManagement :
668642 """Test lifespan management functionality."""
669643
670- @skip_on_linux
671644 async def test_lifespan_startup_shutdown_success (self ):
672645 """Test successful startup and shutdown."""
673646 mock_logger = Mock ()
@@ -694,7 +667,6 @@ async def mock_lifespan(app):
694667
695668 mock_agent_registry .shutdown .assert_called_once ()
696669
697- @skip_on_linux
698670 async def test_lifespan_shutdown_with_import_error (self ):
699671 """Test lifespan handles import errors during shutdown."""
700672 mock_logger = Mock ()
@@ -721,7 +693,6 @@ async def mock_lifespan_with_error(app):
721693 mock_logger .error .assert_called_once ()
722694 assert "Import error during shutdown" in str (mock_logger .error .call_args )
723695
724- @skip_on_linux
725696 async def test_lifespan_shutdown_with_general_exception (self ):
726697 """Test lifespan handles general exceptions during shutdown."""
727698 mock_logger = Mock ()
@@ -750,7 +721,6 @@ async def mock_lifespan_with_exception(app):
750721class TestAzureMonitorConfiguration :
751722 """Test Azure Monitor configuration."""
752723
753- @skip_on_linux
754724 def test_azure_monitor_setup_with_connection_string (self ):
755725 """Test Azure Monitor setup when connection string is available."""
756726 mock_azure_monitor = Mock ()
@@ -764,7 +734,6 @@ def test_azure_monitor_setup_with_connection_string(self):
764734
765735 mock_azure_monitor .use_azure_monitor .assert_called_once ()
766736
767- @skip_on_linux
768737 def test_azure_monitor_setup_without_connection_string (self ):
769738 """Test Azure Monitor setup when connection string is not available."""
770739 mock_azure_monitor = Mock ()
@@ -778,7 +747,6 @@ def test_azure_monitor_setup_without_connection_string(self):
778747
779748 mock_azure_monitor .use_azure_monitor .assert_not_called ()
780749
781- @skip_on_linux
782750 def test_azure_monitor_import_error_handling (self ):
783751 """Test handling of Azure Monitor import errors."""
784752 with patch ('builtins.__import__' ) as mock_import :
@@ -799,7 +767,6 @@ def test_azure_monitor_import_error_handling(self):
799767class TestLoggingConfiguration :
800768 """Test logging configuration."""
801769
802- @skip_on_linux
803770 def test_basic_logging_configuration (self ):
804771 """Test basic logging configuration."""
805772 with patch ('logging.basicConfig' ) as mock_basic_config :
@@ -814,7 +781,6 @@ def test_basic_logging_configuration(self):
814781 mock_basic_config .assert_called_once ()
815782 mock_get_logger .assert_called_once ()
816783
817- @skip_on_linux
818784 def test_logger_creation (self ):
819785 """Test logger creation."""
820786 with patch ('logging.getLogger' ) as mock_get_logger :
@@ -830,7 +796,6 @@ def test_logger_creation(self):
830796class TestFastAPIConfiguration :
831797 """Test FastAPI app configuration."""
832798
833- @skip_on_linux
834799 def test_fastapi_app_creation (self ):
835800 """Test FastAPI app creation."""
836801 from fastapi import FastAPI
@@ -846,7 +811,6 @@ async def mock_lifespan(app):
846811 assert isinstance (app , FastAPI )
847812 assert app .router .lifespan_context is not None
848813
849- @skip_on_linux
850814 def test_cors_middleware_configuration (self ):
851815 """Test CORS middleware configuration."""
852816 from fastapi import FastAPI
@@ -865,7 +829,6 @@ def test_cors_middleware_configuration(self):
865829 assert len (app .user_middleware ) > 0
866830 assert any (middleware .cls == CORSMiddleware for middleware in app .user_middleware )
867831
868- @skip_on_linux
869832 def test_health_check_middleware_addition (self ):
870833 """Test health check middleware addition."""
871834 mock_health_check = Mock ()
@@ -879,7 +842,6 @@ def test_health_check_middleware_addition(self):
879842
880843 mock_health_check .add_health_check_middleware .assert_called_once_with (app )
881844
882- @skip_on_linux
883845 def test_router_inclusion (self ):
884846 """Test router inclusion in FastAPI app."""
885847 from fastapi import FastAPI , APIRouter
@@ -901,7 +863,6 @@ async def test_endpoint():
901863class TestMainExecution :
902864 """Test main execution flow."""
903865
904- @skip_on_linux
905866 def test_uvicorn_configuration (self ):
906867 """Test uvicorn server configuration."""
907868 with patch ('uvicorn.run' ) as mock_uvicorn_run :
@@ -913,7 +874,6 @@ def test_uvicorn_configuration(self):
913874 # Since we're not in __main__, uvicorn.run should not be called
914875 mock_uvicorn_run .assert_not_called ()
915876
916- @skip_on_linux
917877 def test_main_execution_detection (self ):
918878 """Test main execution detection."""
919879 # Test that __name__ detection works
@@ -932,7 +892,6 @@ def test_main_execution_detection(self):
932892class TestErrorHandling :
933893 """Test error handling throughout the application."""
934894
935- @skip_on_linux
936895 def test_import_error_handling (self ):
937896 """Test graceful handling of import errors."""
938897 # Test import error for optional dependencies
@@ -945,7 +904,6 @@ def test_import_error_handling(self):
945904
946905 assert import_error_handled is True
947906
948- @skip_on_linux
949907 def test_environment_variable_handling (self ):
950908 """Test handling of missing environment variables."""
951909 with patch .dict (os .environ , {}, clear = True ):
@@ -962,7 +920,6 @@ def test_environment_variable_handling(self):
962920class TestModuleImports :
963921 """Test module import functionality."""
964922
965- @skip_on_linux
966923 def test_conditional_imports (self ):
967924 """Test conditional imports work correctly."""
968925 # Simulate conditional import
@@ -977,7 +934,6 @@ def test_conditional_imports(self):
977934 assert import_successful is True
978935 assert mock_module is not None
979936
980- @skip_on_linux
981937 def test_module_availability_check (self ):
982938 """Test checking module availability."""
983939 # Test checking if a module is available
@@ -993,23 +949,20 @@ def test_module_availability_check(self):
993949class TestAppModuleBehavior :
994950 """Test app module behavior without importing it."""
995951
996- @skip_on_linux
997952 def test_environment_variable_usage (self ):
998953 """Test how environment variables are used."""
999954 # Test that environment variables are handled correctly
1000955 with patch .dict (os .environ , {'APPLICATIONINSIGHTS_CONNECTION_STRING' : 'InstrumentationKey=test' }):
1001956 conn_str = os .environ .get ("APPLICATIONINSIGHTS_CONNECTION_STRING" )
1002957 assert conn_str == 'InstrumentationKey=test'
1003958
1004- @skip_on_linux
1005959 def test_logging_configuration_simulation (self ):
1006960 """Test logging configuration simulation."""
1007961 with patch ('logging.basicConfig' ) as mock_basic_config :
1008962 # Simulate what app.py does
1009963 logging .basicConfig (level = logging .INFO )
1010964 mock_basic_config .assert_called_once_with (level = logging .INFO )
1011965
1012- @skip_on_linux
1013966 def test_accept_language_parsing (self ):
1014967 """Test Accept-Language header parsing logic."""
1015968 # Simulate the parsing logic from app.py
@@ -1030,7 +983,6 @@ def parse_accept_language(accept_language_header):
1030983class TestRealAppModule :
1031984 """Test the real app module for actual code coverage."""
1032985
1033- @skip_on_linux
1034986 def test_module_level_imports_and_setup (self ):
1035987 """Test module-level imports and setup code."""
1036988 # Test logging setup
@@ -1051,7 +1003,6 @@ def test_module_level_imports_and_setup(self):
10511003 conn_str = os .environ .get ("APPLICATIONINSIGHTS_CONNECTION_STRING" )
10521004 assert conn_str == 'test123'
10531005
1054- @skip_on_linux
10551006 def test_basic_fastapi_functionality (self ):
10561007 """Test that we can create a FastAPI instance and basic functionality."""
10571008 from fastapi import FastAPI
@@ -1073,7 +1024,6 @@ def test_basic_fastapi_functionality(self):
10731024 # Verify middleware was added
10741025 assert len (test_app .user_middleware ) > 0
10751026
1076- @skip_on_linux
10771027 def test_language_parsing_logic (self ):
10781028 """Test the language parsing logic without FastAPI dependencies."""
10791029 # Simulate the language parsing logic from the endpoint
0 commit comments