Test Fixtures

Dexray Insight’s testing framework provides a comprehensive set of fixtures to support different testing scenarios. This guide covers all available fixtures, their usage patterns, and how to create custom fixtures.

Global Fixtures

Configuration Fixtures

These fixtures provide different configuration scenarios for testing:

@pytest.fixture
def minimal_config():
    """Minimal configuration for basic testing"""
    return {
        'analysis': {
            'parallel_execution': {'enabled': False, 'max_workers': 1},
            'timeout': {'module_timeout': 60, 'tool_timeout': 120}
        },
        'modules': {
            'apk_overview': {'enabled': True, 'priority': 1},
            'string_analysis': {'enabled': True, 'priority': 10},
            'permission_analysis': {'enabled': True, 'priority': 20}
        },
        'logging': {'level': 'WARNING'}
    }

@pytest.fixture
def full_config():
    """Complete configuration with all modules enabled"""
    return {
        'analysis': {
            'parallel_execution': {'enabled': True, 'max_workers': 4},
            'timeout': {'module_timeout': 300, 'tool_timeout': 600}
        },
        'modules': {
            'apk_overview': {'enabled': True, 'priority': 1},
            'string_analysis': {'enabled': True, 'priority': 10},
            'permission_analysis': {'enabled': True, 'priority': 20},
            'signature_detection': {'enabled': True, 'priority': 30},
            'manifest_analysis': {'enabled': True, 'priority': 15},
            'library_detection': {'enabled': True, 'priority': 25},
            'tracker_analysis': {'enabled': True, 'priority': 35},
            'behaviour_analysis': {'enabled': True, 'priority': 40},
            'native_analysis': {'enabled': True, 'priority': 50}
        },
        'security': {
            'enable_owasp_assessment': True,
            'assessments': {
                'sensitive_data': {
                    'key_detection': {'enabled': True}
                }
            }
        },
        'logging': {'level': 'DEBUG'}
    }

@pytest.fixture
def performance_config():
    """Configuration optimized for performance testing"""
    return {
        'analysis': {
            'parallel_execution': {'enabled': True, 'max_workers': 8},
            'timeout': {'module_timeout': 30, 'tool_timeout': 60}
        },
        'modules': {
            # Enable only essential modules for performance tests
            'apk_overview': {'enabled': True},
            'string_analysis': {'enabled': True},
            'permission_analysis': {'enabled': True}
        },
        'logging': {'level': 'ERROR'}  # Minimal logging
    }

Usage Example:

def test_basic_analysis(minimal_config):
    """Test basic analysis with minimal configuration"""
    config = Configuration(config_dict=minimal_config)
    engine = AnalysisEngine(config)
    # Test implementation...

Mock Object Fixtures

These fixtures provide mock objects for external dependencies:

@pytest.fixture
def mock_androguard_obj():
    """Mock Androguard object with realistic data"""
    mock = MagicMock()

    # Basic APK information
    mock.get_package.return_value = "com.example.testapp"
    mock.get_version_name.return_value = "1.0.0"
    mock.get_version_code.return_value = 1
    mock.get_min_sdk_version.return_value = 21
    mock.get_target_sdk_version.return_value = 30

    # Permissions
    mock.get_permissions.return_value = [
        "android.permission.INTERNET",
        "android.permission.ACCESS_NETWORK_STATE",
        "android.permission.CAMERA",
        "android.permission.WRITE_EXTERNAL_STORAGE"
    ]

    # Components
    mock.get_activities.return_value = [
        "com.example.testapp.MainActivity",
        "com.example.testapp.SettingsActivity"
    ]
    mock.get_services.return_value = [
        "com.example.testapp.BackgroundService"
    ]
    mock.get_receivers.return_value = [
        "com.example.testapp.BootReceiver"
    ]
    mock.get_providers.return_value = []

    # Native libraries
    mock.get_libraries.return_value = [
        "libtest.so",
        "libcrypto.so",
        "libssl.so"
    ]

    # Validation
    mock.is_valid_apk.return_value = True

    return mock

@pytest.fixture
def mock_analysis_context():
    """Mock analysis context with common data"""
    from dexray_insight.core.base_classes import AnalysisContext, TemporalPaths
    from pathlib import Path

    context = AnalysisContext()
    context.apk_path = "/path/to/test.apk"
    context.module_results = {
        'string_analysis': {
            'urls': ['https://api.example.com', 'http://analytics.com'],
            'ip_addresses': ['192.168.1.1', '8.8.8.8'],
            'domains': ['api.example.com', 'cdn.example.com'],
            'email_addresses': ['contact@example.com'],
            'base64_strings': ['dGVzdCBzdHJpbmc=']
        },
        'permission_analysis': {
            'dangerous_permissions': [
                'android.permission.CAMERA',
                'android.permission.ACCESS_FINE_LOCATION'
            ],
            'normal_permissions': [
                'android.permission.INTERNET',
                'android.permission.ACCESS_NETWORK_STATE'
            ]
        }
    }
    context.shared_data = {
        'processed_strings': True,
        'analysis_timestamp': '2024-01-15T10:30:00Z'
    }

    # Mock temporal paths
    context.temporal_paths = TemporalPaths(
        base_dir=Path("/tmp/analysis"),
        unzipped_dir=Path("/tmp/analysis/unzipped"),
        jadx_dir=Path("/tmp/analysis/jadx"),
        apktool_dir=Path("/tmp/analysis/apktool"),
        logs_dir=Path("/tmp/analysis/logs")
    )

    return context

HTTP Mock Fixtures

Mock external API calls for signature detection and other services:

@pytest.fixture
def mock_virustotal_api():
    """Mock VirusTotal API responses"""
    responses = {
        'clean_file': {
            'response_code': 1,
            'resource': 'test_hash',
            'scan_id': 'test_scan_id',
            'positives': 0,
            'total': 70,
            'scan_date': '2024-01-15 10:30:00',
            'permalink': 'https://virustotal.com/analysis/test',
            'scans': {
                'Avira': {'detected': False, 'version': '1.0', 'result': None},
                'Kaspersky': {'detected': False, 'version': '2.0', 'result': None}
            }
        },
        'malware_file': {
            'response_code': 1,
            'resource': 'malware_hash',
            'positives': 15,
            'total': 70,
            'scan_date': '2024-01-15 10:30:00',
            'scans': {
                'Avira': {'detected': True, 'result': 'Android.Trojan.Banker'},
                'Kaspersky': {'detected': True, 'result': 'Trojan.AndroidOS.Boogr'},
                'McAfee': {'detected': False, 'result': None}
            }
        }
    }

    with patch('requests.get') as mock_get, \
         patch('requests.post') as mock_post:

        def get_side_effect(url, **kwargs):
            mock_response = Mock()
            if 'malware' in url:
                mock_response.json.return_value = responses['malware_file']
            else:
                mock_response.json.return_value = responses['clean_file']
            mock_response.status_code = 200
            return mock_response

        mock_get.side_effect = get_side_effect
        mock_post.return_value.json.return_value = {'response_code': 1, 'scan_id': 'test'}
        mock_post.return_value.status_code = 200

        yield {'get': mock_get, 'post': mock_post, 'responses': responses}

@pytest.fixture
def mock_exodus_api():
    """Mock Exodus Privacy API for tracker detection"""
    tracker_data = {
        'trackers': {
            'google_analytics': {
                'id': 1,
                'name': 'Google Analytics',
                'description': 'Google Analytics is a web analytics service',
                'creation_date': '2018-01-01',
                'code_signature': 'com.google.android.gms.analytics',
                'network_signature': 'google-analytics.com',
                'website': 'https://analytics.google.com',
                'categories': ['Analytics']
            },
            'facebook_ads': {
                'id': 2,
                'name': 'Facebook Ads',
                'description': 'Facebook advertising platform',
                'creation_date': '2018-01-01',
                'code_signature': 'com.facebook.ads',
                'network_signature': 'facebook.com',
                'website': 'https://facebook.com',
                'categories': ['Advertisement']
            }
        }
    }

    with patch('requests.get') as mock_get:
        mock_response = Mock()
        mock_response.json.return_value = tracker_data
        mock_response.status_code = 200
        mock_get.return_value = mock_response

        yield {'get': mock_get, 'data': tracker_data}

Synthetic APK Fixtures

Basic APK Fixtures

@pytest.fixture
def synthetic_apk_builder():
    """APK builder for creating synthetic test APKs"""
    from tests.utils.apk_builder import SyntheticApkBuilder
    return SyntheticApkBuilder()

@pytest.fixture
def basic_synthetic_apk(synthetic_apk_builder, tmp_path):
    """Basic synthetic APK with minimal components"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.test.basic",
        version_name="1.0.0",
        version_code=1,
        framework="Native",
        permissions=[
            "android.permission.INTERNET",
            "android.permission.ACCESS_NETWORK_STATE"
        ],
        activities=["MainActivity"],
        strings=["https://api.example.com", "test@example.com"]
    )

    yield str(apk_path)

    # Cleanup
    if apk_path.exists():
        apk_path.unlink()

@pytest.fixture
def complex_synthetic_apk(synthetic_apk_builder, tmp_path):
    """Complex synthetic APK with many components"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.test.complex",
        version_name="2.1.0",
        version_code=21,
        framework="Native",
        permissions=[
            "android.permission.INTERNET",
            "android.permission.CAMERA",
            "android.permission.ACCESS_FINE_LOCATION",
            "android.permission.READ_CONTACTS",
            "android.permission.WRITE_EXTERNAL_STORAGE",
            "android.permission.RECORD_AUDIO"
        ],
        activities=[
            "MainActivity",
            "SettingsActivity",
            "CameraActivity"
        ],
        services=["BackgroundService", "LocationService"],
        receivers=["BootReceiver", "NetworkReceiver"],
        providers=["DataProvider"],
        native_libraries=["libtest.so", "libcrypto.so"],
        strings=[
            "https://api.example.com/v1",
            "https://analytics.tracking.com",
            "192.168.1.100",
            "8.8.8.8",
            "admin@example.com",
            "support@company.com",
            "dGVzdCBzdHJpbmc=",  # Base64: "test string"
            "cGFzc3dvcmQ=",      # Base64: "password"
            "API_KEY_12345",
            "SECRET_TOKEN_ABCDEF"
        ]
    )

    yield str(apk_path)

    # Cleanup
    if apk_path.exists():
        apk_path.unlink()

Framework-Specific APK Fixtures

@pytest.fixture
def flutter_apk(synthetic_apk_builder, tmp_path):
    """Synthetic Flutter APK"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.test.flutter",
        framework="Flutter",
        version_name="1.0.0",
        native_libraries=[
            "libflutter.so",
            "libapp.so",
            "lib arm64-v8a/libflutter.so"
        ],
        activities=["io.flutter.embedding.android.FlutterActivity"],
        strings=[
            "flutter",
            "dart:ui",
            "Flutter Engine",
            "https://flutter.dev/api"
        ]
    )

    yield str(apk_path)
    if apk_path.exists():
        apk_path.unlink()

@pytest.fixture
def react_native_apk(synthetic_apk_builder, tmp_path):
    """Synthetic React Native APK"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.test.reactnative",
        framework="React Native",
        version_name="1.0.0",
        native_libraries=[
            "libreactnativejni.so",
            "libhermes.so",
            "libjsc.so"
        ],
        activities=["com.facebook.react.ReactActivity"],
        strings=[
            "React Native",
            "javascript",
            "metro",
            "https://reactnative.dev"
        ]
    )

    yield str(apk_path)
    if apk_path.exists():
        apk_path.unlink()

@pytest.fixture
def xamarin_apk(synthetic_apk_builder, tmp_path):
    """Synthetic Xamarin APK"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.test.xamarin",
        framework="Xamarin",
        version_name="1.0.0",
        native_libraries=[
            "libmonodroid.so",
            "libmonosgen-2.0.so",
            "libxamarin-app.so"
        ],
        activities=["crc64.MainActivity"],
        strings=[
            "Xamarin",
            "Mono",
            "System.dll",
            "mscorlib.dll"
        ]
    )

    yield str(apk_path)
    if apk_path.exists():
        apk_path.unlink()

Specialized Test Fixtures

Security Testing Fixtures

@pytest.fixture
def malware_like_apk(synthetic_apk_builder, tmp_path):
    """APK with malware-like characteristics"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.suspicious.app",
        version_name="1.0.0",
        permissions=[
            "android.permission.READ_CONTACTS",
            "android.permission.READ_SMS",
            "android.permission.SEND_SMS",
            "android.permission.ACCESS_FINE_LOCATION",
            "android.permission.CAMERA",
            "android.permission.RECORD_AUDIO",
            "android.permission.WRITE_EXTERNAL_STORAGE",
            "android.permission.SYSTEM_ALERT_WINDOW"
        ],
        activities=["MainActivity", "HiddenActivity"],
        services=["StealthService"],
        receivers=["BootReceiver", "SmsReceiver"],
        strings=[
            "https://malicious-c2.com/upload",
            "http://evil-server.net/data",
            "credit_card_number",
            "social_security_number",
            "password123",
            "admin_password",
            "192.168.1.100",
            "10.0.0.1",
            # Base64 encoded suspicious strings
            "cGFzc3dvcmQ=",           # "password"
            "YWRtaW5fcGFzc3dvcmQ=",   # "admin_password"
            "c2VjcmV0X2tleQ==",       # "secret_key"
            # Fake API keys and tokens
            "AIzaSyDexampleAPIkey123456789",
            "ghp_exampleGitHubToken123456789",
            "xoxb-slack-bot-token-example",
            "sk_test_stripe_key_example123"
        ],
        intent_filters=[
            {
                "action": "android.intent.action.BOOT_COMPLETED",
                "category": "android.intent.category.DEFAULT"
            },
            {
                "action": "android.provider.Telephony.SMS_RECEIVED",
                "priority": "1000"
            }
        ]
    )

    yield str(apk_path)
    if apk_path.exists():
        apk_path.unlink()

@pytest.fixture
def privacy_invasive_apk(synthetic_apk_builder, tmp_path):
    """APK with privacy-invasive patterns"""
    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.privacy.invasive",
        permissions=[
            "android.permission.ACCESS_FINE_LOCATION",
            "android.permission.READ_CONTACTS",
            "android.permission.READ_PHONE_STATE",
            "android.permission.GET_ACCOUNTS",
            "android.permission.READ_CALENDAR"
        ],
        strings=[
            "https://analytics.tracking-company.com/collect",
            "device_id",
            "imei_number",
            "phone_number",
            "contact_list",
            "location_data",
            "user_behavior"
        ],
        # Include multiple tracking libraries
        tracking_libraries=[
            "com.google.android.gms.analytics",
            "com.facebook.appevents",
            "com.flurry.android",
            "com.crashlytics.android"
        ]
    )

    yield str(apk_path)
    if apk_path.exists():
        apk_path.unlink()

Performance Testing Fixtures

@pytest.fixture
def large_apk(synthetic_apk_builder, tmp_path):
    """Large APK for performance testing"""
    # Generate many strings to simulate large APK
    many_strings = []
    for i in range(1000):
        many_strings.extend([
            f"https://api{i}.example.com",
            f"user{i}@example.com",
            f"192.168.1.{i % 255}",
            f"string_pattern_{i}",
            f"base64_encoded_{i}="
        ])

    # Generate many activities
    many_activities = [f"Activity{i}" for i in range(50)]

    # Generate many permissions
    many_permissions = [
        "android.permission.INTERNET",
        "android.permission.ACCESS_NETWORK_STATE",
        "android.permission.WRITE_EXTERNAL_STORAGE"
    ]
    many_permissions.extend([f"com.example.CUSTOM_PERM_{i}" for i in range(20)])

    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name="com.test.large",
        version_name="1.0.0",
        permissions=many_permissions,
        activities=many_activities,
        services=[f"Service{i}" for i in range(20)],
        receivers=[f"Receiver{i}" for i in range(10)],
        native_libraries=[f"lib{i}.so" for i in range(10)],
        strings=many_strings
    )

    yield str(apk_path)
    if apk_path.exists():
        apk_path.unlink()

@pytest.fixture
def multiple_synthetic_apks(synthetic_apk_builder, tmp_path):
    """Multiple APKs for parallel processing tests"""
    apks = []

    for i in range(5):
        apk_path = synthetic_apk_builder.build_apk(
            output_dir=tmp_path,
            package_name=f"com.test.parallel{i}",
            version_name="1.0.0",
            framework="Native",
            permissions=["android.permission.INTERNET"],
            activities=[f"MainActivity{i}"],
            strings=[f"https://api{i}.example.com"]
        )
        apks.append(str(apk_path))

    yield apks

    # Cleanup all APKs
    for apk_path in apks:
        path_obj = Path(apk_path)
        if path_obj.exists():
            path_obj.unlink()

Data Fixtures

Sample Result Fixtures

@pytest.fixture
def sample_apk_overview_result():
    """Sample APK overview analysis result"""
    from dexray_insight.results.apk_overview_results import ApkOverviewResult
    from dexray_insight.core.base_classes import AnalysisStatus

    return ApkOverviewResult(
        module_name="apk_overview",
        status=AnalysisStatus.SUCCESS,
        execution_time=2.5,
        package_name="com.example.testapp",
        version_name="1.0.0",
        version_code=1,
        min_sdk_version=21,
        target_sdk_version=30,
        permissions=[
            "android.permission.INTERNET",
            "android.permission.CAMERA",
            "android.permission.ACCESS_FINE_LOCATION"
        ],
        activities=[
            "com.example.testapp.MainActivity",
            "com.example.testapp.SettingsActivity"
        ],
        services=["com.example.testapp.BackgroundService"],
        receivers=["com.example.testapp.BootReceiver"],
        providers=[],
        native_libraries=["libtest.so", "libcrypto.so"],
        framework="Native"
    )

@pytest.fixture
def sample_string_analysis_result():
    """Sample string analysis result"""
    from dexray_insight.results.string_analysis_results import StringAnalysisResult
    from dexray_insight.core.base_classes import AnalysisStatus

    return StringAnalysisResult(
        module_name="string_analysis",
        status=AnalysisStatus.SUCCESS,
        execution_time=5.2,
        urls=[
            "https://api.example.com/v1",
            "https://analytics.tracking.com",
            "http://cdn.example.com"
        ],
        ip_addresses=["192.168.1.1", "8.8.8.8", "1.1.1.1"],
        email_addresses=["contact@example.com", "support@company.org"],
        domains=["api.example.com", "analytics.tracking.com", "cdn.example.com"],
        base64_strings=["dGVzdCBzdHJpbmc=", "cGFzc3dvcmQ="],
        total_strings=1247
    )

@pytest.fixture
def sample_security_assessment_result():
    """Sample security assessment result"""
    from dexray_insight.results.security_assessment_results import SecurityAssessmentResult
    from dexray_insight.core.base_classes import AnalysisStatus

    return SecurityAssessmentResult(
        module_name="security_assessment",
        status=AnalysisStatus.SUCCESS,
        execution_time=12.8,
        risk_level="HIGH",
        vulnerability_count=5,
        owasp_findings=[
            {
                'category': 'M2-Insecure-Data-Storage',
                'description': 'Hardcoded API key detected in strings',
                'severity': 'HIGH',
                'evidence': 'AIzaSyDexampleAPIkey123456789'
            },
            {
                'category': 'M4-Insecure-Authentication',
                'description': 'Hardcoded password found',
                'severity': 'CRITICAL',
                'evidence': 'admin_password'
            }
        ],
        hardcoded_secrets=[
            {
                'type': 'Google API Key',
                'value': 'AIzaSyDexampleAPIkey123456789',
                'severity': 'HIGH',
                'location': 'strings.xml:42',
                'context': 'API configuration'
            },
            {
                'type': 'Hardcoded Password',
                'value': 'admin_password',
                'severity': 'CRITICAL',
                'location': 'AuthManager.java:156',
                'context': 'Authentication logic'
            }
        ],
        recommendations=[
            "Remove hardcoded API keys and use secure configuration",
            "Implement proper password management",
            "Review data storage security"
        ]
    )

Test Environment Fixtures

@pytest.fixture(scope="session")
def test_environment():
    """Set up test environment configuration"""
    import os
    import tempfile
    from pathlib import Path

    # Create temporary directories
    temp_base = Path(tempfile.mkdtemp(prefix="dexray_test_"))

    env_config = {
        'temp_dir': temp_base,
        'output_dir': temp_base / "outputs",
        'cache_dir': temp_base / "cache",
        'logs_dir': temp_base / "logs"
    }

    # Create directories
    for dir_path in env_config.values():
        if isinstance(dir_path, Path):
            dir_path.mkdir(exist_ok=True)

    # Set environment variables
    original_env = {}
    test_env_vars = {
        'DEXRAY_TEST_MODE': 'true',
        'DEXRAY_TEMP_DIR': str(env_config['temp_dir']),
        'DEXRAY_OUTPUT_DIR': str(env_config['output_dir']),
        'NO_COLOR': '1'  # Disable colored output in tests
    }

    for key, value in test_env_vars.items():
        original_env[key] = os.environ.get(key)
        os.environ[key] = value

    yield env_config

    # Cleanup
    import shutil
    shutil.rmtree(temp_base, ignore_errors=True)

    # Restore environment variables
    for key, original_value in original_env.items():
        if original_value is None:
            os.environ.pop(key, None)
        else:
            os.environ[key] = original_value

@pytest.fixture
def isolated_filesystem(tmp_path):
    """Isolated filesystem for file operations"""
    import os
    original_cwd = os.getcwd()

    # Change to temporary directory
    os.chdir(tmp_path)

    # Create common test directories
    (tmp_path / "inputs").mkdir()
    (tmp_path / "outputs").mkdir()
    (tmp_path / "temp").mkdir()

    yield tmp_path

    # Restore original working directory
    os.chdir(original_cwd)

Parameterized Fixtures

Multi-Configuration Fixtures

@pytest.fixture(params=[
    'minimal_config',
    'full_config',
    'performance_config'
])
def various_configs(request):
    """Fixture providing different configuration scenarios"""
    return request.getfixturevalue(request.param)

@pytest.fixture(params=[
    ('Native', []),
    ('Flutter', ['libflutter.so', 'libapp.so']),
    ('React Native', ['libreactnativejni.so', 'libhermes.so']),
    ('Xamarin', ['libmonodroid.so', 'libmonosgen-2.0.so']),
    ('Unity', ['libunity.so', 'libil2cpp.so'])
])
def framework_apk_data(request):
    """Framework-specific APK test data"""
    framework, native_libs = request.param
    return {
        'framework': framework,
        'native_libraries': native_libs,
        'package_name': f"com.test.{framework.lower().replace(' ', '')}",
        'activities': [f"com.{framework.lower()}.MainActivity"] if framework != 'Native' else ['MainActivity']
    }

@pytest.fixture(params=[1, 4, 8])
def parallel_worker_counts(request):
    """Different parallel worker configurations"""
    return {
        'analysis': {
            'parallel_execution': {
                'enabled': True,
                'max_workers': request.param
            }
        }
    }

APK Complexity Levels

@pytest.fixture(params=[
    {
        'name': 'simple',
        'permissions': 3,
        'activities': 2,
        'strings': 20,
        'native_libs': 1
    },
    {
        'name': 'medium',
        'permissions': 8,
        'activities': 5,
        'strings': 100,
        'native_libs': 3
    },
    {
        'name': 'complex',
        'permissions': 15,
        'activities': 12,
        'strings': 500,
        'native_libs': 8
    }
])
def apk_complexity_levels(request, synthetic_apk_builder, tmp_path):
    """APKs with different complexity levels"""
    params = request.param

    # Generate appropriate amounts of test data
    permissions = [
        "android.permission.INTERNET",
        "android.permission.ACCESS_NETWORK_STATE"
    ] + [f"com.example.PERM_{i}" for i in range(params['permissions'] - 2)]

    activities = [f"Activity{i}" for i in range(params['activities'])]

    strings = [f"https://api{i}.example.com" for i in range(params['strings'])]

    native_libs = [f"lib{i}.so" for i in range(params['native_libs'])]

    apk_path = synthetic_apk_builder.build_apk(
        output_dir=tmp_path,
        package_name=f"com.test.{params['name']}",
        version_name="1.0.0",
        permissions=permissions,
        activities=activities,
        strings=strings,
        native_libraries=native_libs
    )

    yield {
        'apk_path': str(apk_path),
        'complexity': params['name'],
        'expected_counts': params
    }

    if apk_path.exists():
        apk_path.unlink()

Custom Fixture Creation

Creating Module-Specific Fixtures

# For string analysis module tests
@pytest.fixture
def string_analysis_test_data():
    """Test data for string analysis module"""
    return {
        'input_strings': [
            "Visit https://example.com for more info",
            "Contact us at support@company.org",
            "Server IP: 192.168.1.100",
            "Base64 data: dGVzdCBkYXRh",
            "API endpoint: https://api.service.com/v2",
            "Debug server: http://10.0.0.1:8080",
            "Email: admin@test.local"
        ],
        'expected_urls': [
            "https://example.com",
            "https://api.service.com/v2",
            "http://10.0.0.1:8080"
        ],
        'expected_emails': [
            "support@company.org",
            "admin@test.local"
        ],
        'expected_ips': [
            "192.168.1.100",
            "10.0.0.1"
        ],
        'expected_base64': [
            "dGVzdCBkYXRh"
        ]
    }

# For security assessment tests
@pytest.fixture
def security_test_secrets():
    """Test secrets for security assessment"""
    return {
        'api_keys': [
            "AIzaSyDexampleGoogleAPIkey123456789",
            "ghp_exampleGitHubPersonalAccessToken123",
            "xoxb-example-slack-bot-token-123456"
        ],
        'passwords': [
            "password123",
            "admin_password",
            "default_pass"
        ],
        'certificates': [
            "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBg...",
            "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKC..."
        ],
        'database_urls': [
            "mongodb://user:pass@localhost:27017/db",
            "postgresql://admin:secret@db.example.com:5432/app"
        ]
    }

Factory Fixtures

@pytest.fixture
def apk_factory(synthetic_apk_builder, tmp_path):
    """Factory for creating APKs with custom parameters"""
    created_apks = []

    def create_apk(**kwargs):
        # Default parameters
        defaults = {
            'output_dir': tmp_path,
            'package_name': 'com.test.factory',
            'version_name': '1.0.0',
            'framework': 'Native',
            'permissions': ['android.permission.INTERNET'],
            'activities': ['MainActivity']
        }

        # Merge with provided parameters
        defaults.update(kwargs)

        apk_path = synthetic_apk_builder.build_apk(**defaults)
        created_apks.append(apk_path)
        return str(apk_path)

    yield create_apk

    # Cleanup all created APKs
    for apk_path in created_apks:
        if apk_path.exists():
            apk_path.unlink()

@pytest.fixture
def mock_factory():
    """Factory for creating various mock objects"""
    def create_mock_result(module_name, status='SUCCESS', **kwargs):
        from dexray_insight.core.base_classes import BaseResult, AnalysisStatus

        mock_result = Mock(spec=BaseResult)
        mock_result.module_name = module_name
        mock_result.status = getattr(AnalysisStatus, status)
        mock_result.execution_time = kwargs.get('execution_time', 1.0)
        mock_result.error_message = kwargs.get('error_message')

        # Add custom attributes
        for key, value in kwargs.items():
            if key not in ['execution_time', 'error_message']:
                setattr(mock_result, key, value)

        return mock_result

    def create_mock_context(apk_path="/test/app.apk", **module_results):
        from dexray_insight.core.base_classes import AnalysisContext

        context = AnalysisContext()
        context.apk_path = apk_path
        context.module_results = module_results
        context.shared_data = {}

        return context

    return {
        'result': create_mock_result,
        'context': create_mock_context
    }

Using Fixtures Effectively

Fixture Composition

@pytest.fixture
def complete_analysis_setup(
    full_config,
    complex_synthetic_apk,
    mock_virustotal_api,
    test_environment
):
    """Complete setup for full analysis testing"""
    from dexray_insight.core.configuration import Configuration
    from dexray_insight.core.analysis_engine import AnalysisEngine

    # Configure analysis engine
    config = Configuration(config_dict=full_config)
    engine = AnalysisEngine(config)

    return {
        'engine': engine,
        'apk_path': complex_synthetic_apk,
        'config': config,
        'environment': test_environment,
        'mocked_apis': mock_virustotal_api
    }

def test_complete_analysis_with_mocks(complete_analysis_setup):
    """Test complete analysis with all mocks"""
    setup = complete_analysis_setup

    # Run analysis
    results = setup['engine'].analyze_apk(setup['apk_path'])

    # Verify results
    assert results is not None
    assert results.apk_overview is not None
    assert results.string_analysis is not None

    # Verify API mocks were called
    setup['mocked_apis']['get'].assert_called()

Fixture Scoping and Performance

# Session-scoped fixture for expensive setup
@pytest.fixture(scope="session")
def expensive_test_data():
    """Expensive test data created once per test session"""
    # This runs once for the entire test session
    large_data = generate_large_test_dataset()
    return large_data

# Module-scoped fixture for per-module setup
@pytest.fixture(scope="module")
def module_test_environment():
    """Test environment per module"""
    # This runs once per test module
    env = setup_test_environment()
    yield env
    cleanup_test_environment(env)

# Function-scoped fixture (default) for per-test setup
@pytest.fixture
def test_specific_data():
    """Data specific to each test"""
    # This runs for each test function
    return generate_test_specific_data()

Best Practices for Fixtures

Naming and Organization:

  1. Descriptive names - Fixture names should clearly indicate what they provide

  2. Consistent patterns - Use consistent naming patterns across the test suite

  3. Logical grouping - Group related fixtures together

  4. Clear documentation - Document fixture purpose and usage

Resource Management:

  1. Proper cleanup - Always clean up resources in fixture teardown

  2. Appropriate scoping - Use the right fixture scope for performance

  3. Avoid side effects - Fixtures should not have unintended side effects

  4. Isolation - Each fixture should be independent

Performance Considerations:

  1. Cache expensive operations - Use session or module scoped fixtures for expensive setup

  2. Lazy loading - Only create resources when actually needed

  3. Parallel safety - Ensure fixtures work correctly with parallel test execution

  4. Memory management - Clean up large objects to prevent memory issues

The comprehensive fixture system in Dexray Insight enables thorough testing across all components while maintaining test isolation and performance.