Skip to main content
Each platform has unique testing requirements, tools, and workflows. This guide covers platform-specific testing considerations for Mullvad VPN.

Desktop Testing (Linux, macOS, Windows)

Prerequisites

All Platforms

  • Latest stable Rust from https://rustup.rs/
  • Node.js 16+ and npm 8.3+
  • Protocol Buffers compiler

macOS

Install dependencies:
Wireshark for packet capture:
VM setup with Tart:

Linux

Fedora:
Debian/Ubuntu:
Note for Debian: sysctl is only invokable by root by default. VM setup with QEMU:

Windows

Windows VMs are typically run from Linux hosts using QEMU. Build test-runner for Windows:

Running Desktop Tests

Unit Tests

JavaScript/TypeScript tests:
Run specific test file:
Watch mode:

E2E Tests

Mocked backend tests:
Run specific test suite:
Run with UI visible:
Debug mode:
Installed app tests:

VM-Based Integration Tests

Setup test environment:
Run tests on Linux VM:
Run tests on macOS VM:
Run specific test:

Platform-Specific Test Areas

macOS-Specific Tests

Tests in test-manager/src/tests/macos.rs:
  • Launch daemon functionality
  • Keychain integration
  • System extension loading
  • Network extension behavior
  • Notification permissions

Windows-Specific Tests

Tests in test-manager/src/tests/windows.rs:
  • Windows Filtering Platform (WFP) integration
  • Service installation and management
  • TAP adapter functionality
  • Driver loading and unloading
  • Windows firewall integration

Linux-Specific Tests

Tests in test-manager/src/tests/split_tunnel.rs:
  • Split tunneling via cgroups
  • Network namespace management
  • iptables/nftables rules
  • systemd integration
  • D-Bus communication

Android Testing

Prerequisites

  • Android Studio or Android SDK command-line tools
  • Java Development Kit (JDK) 17+
  • Android device or emulator
  • Valid Mullvad account for e2e tests

Test Structure

Android tests are organized by module in android/lib/*/src/test/:
  • app/src/test - Main application unit tests
  • lib/billing/src/test - Billing functionality tests
  • lib/feature/*/src/test - Feature module tests
  • test/e2e - End-to-end instrumented tests

Running Android Tests

Unit Tests

Run all unit tests:
Run tests for specific module:
Run with coverage:

Instrumented Tests

Run on connected device:

End-to-End Tests

Configure test accounts: Add to ~/.gradle/gradle.properties:
Run e2e tests:
Run via ADB (for manual APK installation):

Firebase Test Lab

Run tests on multiple devices using Firebase Test Lab: Setup:
Run tests:

Android Test Artifacts

Test artifacts are stored on device:
Artifacts include:
  • Screenshots
  • Logcat output
  • Network traffic logs
  • Database dumps

Android-Specific Test Areas

Feature tests:
  • Account management (lib/feature/account/impl/src/test)
  • Login flow (lib/feature/login/impl/src/test)
  • Device management (lib/feature/managedevices/impl/src/test)
  • Split tunneling (lib/feature/splittunneling/impl/src/test)
  • Multi-hop configuration (lib/feature/multihop/impl/src/test)
  • DAITA support (lib/feature/daita/impl/src/test)
Compose UI tests: Android uses Jetpack Compose with UI testing support:

iOS Testing

Prerequisites

  • macOS with Xcode installed
  • iOS Simulator or physical iOS device
  • Xcode Command Line Tools
  • CocoaPods (if used)

Test Structure

iOS tests are organized by framework:
  • MullvadRESTTests - REST API client tests
  • MullvadRustRuntimeTests - Rust FFI integration tests
  • MullvadPostQuantumTests - Post-quantum cryptography tests
  • MullvadVPNTests - Main app logic tests
  • MullvadVPNScreenshotTests - UI screenshot tests

Running iOS Tests

Via Xcode

  1. Open ios/MullvadVPN.xcodeproj
  2. Select test scheme (e.g., MullvadVPN)
  3. Press Cmd + U to run tests

Via Command Line

Run all tests:
Run specific test target:
Run on physical device:
List available simulators:

Via xcodebuild with JSON output

iOS-Specific Test Areas

REST API Tests (MullvadRESTTests)

Test files:
  • AppVersionServiceTests.swift - App version API
  • DefaultLocationServiceTests.swift - Location service
  • ServerRelayTests.swift - Relay server selection
  • RetryStrategyTests.swift - Network retry logic
  • ShadowsocksCacheCleanerTests.swift - Cache management

Rust Runtime Tests (MullvadRustRuntimeTests)

Test files:
  • EphemeralPeerExchangeActorTests.swift - Peer exchange protocol
  • TunnelObfuscationTests.swift - Tunnel obfuscation

Network Extension Tests

iOS Network Extension requires special testing considerations:
  • Must test on actual iOS device for full functionality
  • Simulator has limited VPN capabilities
  • Requires provisioning profiles and certificates

UI Testing on iOS

Screenshot tests:
XCUITest framework:

Rust Core Testing

All platforms share Rust core components that require testing.

Running Rust Tests

All workspace tests:
Specific crate:
With verbose output:
Documentation tests:

Platform-Specific Rust Tests

Test only on specific platform:

Cross-Platform Test Automation

GitHub Actions

Tests run automatically on pull requests and scheduled builds. View test results:
  • Check the “Checks” tab on pull requests
  • Review GitHub Actions workflow runs
Test workflows:
  • android-app.yml - Android unit and instrumented tests
  • desktop-*.yml - Desktop tests for each platform
  • ios-*.yml - iOS build and test workflows

Test by Version Script

Automate testing of specific versions:
This script:
  • Downloads pre-built application packages
  • Sets up test VMs
  • Runs the test suite
  • Reports results

Debugging Platform-Specific Issues

Desktop Debugging

Enable debug logging:
Electron debug mode:

Android Debugging

Logcat filtering:
Debug specific test:

iOS Debugging

Console output:
Simulator logs:

Best Practices

  1. Test on actual hardware - Especially for VPN functionality
  2. Use platform-specific CI - Each platform has its own test requirements
  3. Mock network dependencies - For faster, more reliable unit tests
  4. Test permission flows - Each platform handles permissions differently
  5. Verify platform integration - System extensions, services, and permissions
  6. Test upgrade paths - Ensure smooth updates from previous versions
  7. Monitor test flakiness - Platform-specific timing issues can cause flaky tests