Mobile Proxies for Food Delivery App Testing (iOS and Android)

Mobile Proxies for Food Delivery App Testing (iOS and Android)

Food delivery apps operate differently across geographies. A restaurant app that works flawlessly in Singapore may show different pricing in Malaysia, different UI layouts in Thailand, or different available features in the Philippines. For development teams, QA engineers, and product managers building or maintaining food delivery applications, testing these geo-specific behaviors requires authentic mobile network access from each target country.

Mobile proxies solve this problem by routing app traffic through real mobile carrier IPs in specific countries, enabling comprehensive testing without physically being in each market.

Why Standard Testing Tools Fall Short

The Problem with Emulators and VPNs

Traditional testing approaches have significant limitations for food delivery apps:

Emulators and Simulators

  • Cannot replicate real mobile network conditions
  • Missing carrier-specific network configurations
  • Easily detected by apps that check device authenticity
  • Do not provide real geographic IP addresses

VPN Services

  • Use datacenter or residential IPs, not mobile IPs
  • Easily detected by food delivery platform APIs
  • Often blocked by mobile-first applications
  • Cannot simulate carrier-specific behaviors

Physical Device Labs

  • Expensive to maintain devices across countries
  • Logistics of SIM card management across SEA
  • Limited scale for concurrent testing
  • Cannot quickly switch between locations

What Mobile Proxies Provide

Mobile proxies from DataResearchTools address all these limitations:

CapabilityTraditional TestingMobile Proxies
Real mobile carrier IPNoYes
Country-specific targetingLimitedFull SEA coverage
Carrier selectionNoYes (Singtel, Maxis, AIS, etc.)
App detection bypassOften caughtAppears as genuine user
ScaleLimited by hardwareUnlimited concurrent sessions
Switch locationsPhysical device swapAPI call
CostHigh (device farm)Affordable per-session pricing

Setting Up App Testing with Mobile Proxies

iOS Configuration

Configure an iOS device or simulator to route traffic through a mobile proxy:

Settings > Wi-Fi > [Your Network] > Configure Proxy > Manual

Server: sg-mobile.dataresearchtools.com
Port: 8080
Authentication: On
Username: your_username
Password: your_password

For programmatic testing with XCUITest:

// Configure proxy for UITest environment
class FoodDeliveryAppTests: XCTestCase {

    override func setUp() {
        super.setUp()
        let app = XCUIApplication()

        // Pass proxy configuration as launch arguments
        app.launchArguments += [
            "-proxyHost", "sg-mobile.dataresearchtools.com",
            "-proxyPort", "8080",
            "-proxyUser", "your_username",
            "-proxyPass", "your_password"
        ]

        app.launch()
    }

    func testSingaporeRestaurantListing() {
        // Test with Singapore mobile IP
        // App should show Singapore restaurants and SGD pricing
        let app = XCUIApplication()
        let restaurantList = app.tables["restaurantListTable"]

        XCTAssertTrue(restaurantList.exists)
        XCTAssertTrue(restaurantList.cells.count > 0)

        // Verify currency is SGD
        let firstCell = restaurantList.cells.firstMatch
        XCTAssertTrue(firstCell.staticTexts.matching(
            NSPredicate(format: "label CONTAINS 'S$'")
        ).count > 0)
    }
}

Android Configuration

For Android devices, configure the proxy through Wi-Fi settings or programmatically:

// Configure proxy in Android instrumentation tests
class FoodDeliveryAppTest {

    @Before
    fun setUp() {
        // Set system proxy
        System.setProperty("http.proxyHost", "sg-mobile.dataresearchtools.com")
        System.setProperty("http.proxyPort", "8080")
        System.setProperty("https.proxyHost", "sg-mobile.dataresearchtools.com")
        System.setProperty("https.proxyPort", "8080")
    }

    @Test
    fun testMalaysianMenuPricing() {
        // Switch to Malaysian proxy
        System.setProperty("http.proxyHost", "my-mobile.dataresearchtools.com")

        // Launch app and verify MYR pricing
        val scenario = ActivityScenario.launch(MainActivity::class.java)
        onView(withId(R.id.restaurantList))
            .check(matches(isDisplayed()))

        // Verify Malaysian Ringgit pricing
        onView(withId(R.id.priceText))
            .check(matches(withText(containsString("RM"))))
    }
}

Using Appium for Cross-Platform Testing

from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
import time

class FoodDeliveryAppTester:
    def __init__(self, platform="android"):
        self.proxy_configs = {
            "SG": "sg-mobile.dataresearchtools.com:8080",
            "MY": "my-mobile.dataresearchtools.com:8080",
            "TH": "th-mobile.dataresearchtools.com:8080",
            "PH": "ph-mobile.dataresearchtools.com:8080",
            "ID": "id-mobile.dataresearchtools.com:8080"
        }

        if platform == "android":
            self.caps = {
                "platformName": "Android",
                "deviceName": "emulator-5554",
                "app": "/path/to/food-delivery.apk",
                "automationName": "UiAutomator2",
                "noReset": False
            }
        else:
            self.caps = {
                "platformName": "iOS",
                "deviceName": "iPhone 15",
                "app": "/path/to/FoodDelivery.app",
                "automationName": "XCUITest",
                "noReset": False
            }

    def configure_proxy(self, country):
        """Set proxy for a specific country."""
        proxy = self.proxy_configs.get(country)
        if proxy:
            host, port = proxy.split(":")
            # Configure device proxy settings
            self._set_device_proxy(host, int(port))

    def test_geo_content(self, country):
        """Test that app shows correct geo-targeted content."""
        self.configure_proxy(country)
        driver = webdriver.Remote("http://localhost:4723/wd/hub", self.caps)

        try:
            # Wait for app to load
            time.sleep(5)

            # Grant location permission if prompted
            self._handle_permissions(driver)

            # Check restaurant listings load
            restaurant_list = driver.find_element(
                AppiumBy.ID, "restaurant_list_view"
            )
            assert restaurant_list.is_displayed(), \
                f"Restaurant list not displayed for {country}"

            # Count visible restaurants
            restaurants = driver.find_elements(
                AppiumBy.ID, "restaurant_card"
            )
            print(f"{country}: Found {len(restaurants)} restaurants")

            # Verify currency matches country
            price_element = driver.find_element(
                AppiumBy.ID, "delivery_fee_text"
            )
            currency_map = {
                "SG": "S$", "MY": "RM", "TH": "฿",
                "PH": "₱", "ID": "Rp"
            }
            expected_currency = currency_map.get(country, "")
            assert expected_currency in price_element.text, \
                f"Wrong currency for {country}: {price_element.text}"

            return True

        except Exception as e:
            print(f"Test failed for {country}: {e}")
            return False

        finally:
            driver.quit()

Key Testing Scenarios for Food Delivery Apps

1. Geo-Targeting Verification

Verify that the app serves correct content based on user location:

def test_geo_targeting(tester):
    """Verify geo-targeting across all SEA markets."""
    results = {}

    test_cases = {
        "SG": {
            "expected_currency": "SGD",
            "expected_language": "en",
            "expected_restaurants": ["McDonald's", "KFC"],  # Known chains
            "expected_payment": ["GrabPay", "PayNow"]
        },
        "MY": {
            "expected_currency": "MYR",
            "expected_language": "en",
            "expected_restaurants": ["McDonald's", "KFC"],
            "expected_payment": ["GrabPay", "Touch 'n Go"]
        },
        "TH": {
            "expected_currency": "THB",
            "expected_language": "th",
            "expected_restaurants": ["McDonald's", "KFC"],
            "expected_payment": ["GrabPay", "PromptPay"]
        },
        "ID": {
            "expected_currency": "IDR",
            "expected_language": "id",
            "expected_restaurants": ["McDonald's", "KFC"],
            "expected_payment": ["GoPay", "OVO"]
        }
    }

    for country, expectations in test_cases.items():
        tester.configure_proxy(country)
        result = tester.verify_content(expectations)
        results[country] = {
            "passed": all(result.values()),
            "details": result
        }

    return results

2. Price Localization Testing

Ensure prices are correctly displayed in local currency:

def test_price_localization(tester, restaurant_chain="McDonald's"):
    """Test that prices are correctly localized."""
    price_results = {}

    for country in ["SG", "MY", "TH", "PH", "ID"]:
        tester.configure_proxy(country)

        # Search for the chain restaurant
        menu = tester.search_and_get_menu(restaurant_chain)

        if menu:
            price_results[country] = {
                "currency_correct": menu["currency"] == get_expected_currency(country),
                "prices_reasonable": all(
                    is_price_reasonable(item["price"], country)
                    for item in menu["items"]
                ),
                "formatting_correct": all(
                    is_format_correct(item["price_display"], country)
                    for item in menu["items"]
                ),
                "sample_prices": menu["items"][:3]
            }

    return price_results

def is_price_reasonable(price, country):
    """Check if a price is within reasonable range for a country."""
    ranges = {
        "SG": (2, 50),      # SGD
        "MY": (3, 100),     # MYR
        "TH": (20, 500),    # THB
        "PH": (50, 1000),   # PHP
        "ID": (5000, 200000) # IDR
    }
    min_price, max_price = ranges.get(country, (0, float("inf")))
    return min_price <= price <= max_price

3. Delivery Zone Boundary Testing

Test app behavior at delivery zone boundaries:

def test_delivery_boundaries(tester, country="SG"):
    """Test delivery availability at zone boundaries."""
    tester.configure_proxy(country)

    # Test points at varying distances from restaurant
    test_points = {
        "within_zone": (1.3521, 103.8198),    # CBD Singapore
        "zone_edge": (1.3800, 103.8500),       # Slightly outside
        "outside_zone": (1.4500, 103.9000),    # Clearly outside
        "border_area": (1.4400, 103.7700)      # Near country border
    }

    results = {}
    for label, coords in test_points.items():
        tester.set_location(coords[0], coords[1])
        time.sleep(3)

        delivery_available = tester.check_delivery_available()
        restaurant_count = tester.count_available_restaurants()
        delivery_fee = tester.get_sample_delivery_fee()

        results[label] = {
            "coordinates": coords,
            "delivery_available": delivery_available,
            "restaurants_shown": restaurant_count,
            "sample_delivery_fee": delivery_fee
        }

    return results

4. Promotion Display Testing

Verify promotions are correctly shown for each market:

def test_promotion_display(tester):
    """Test that promotions display correctly per market."""
    results = {}

    for country in ["SG", "MY", "TH", "PH", "ID"]:
        tester.configure_proxy(country)
        time.sleep(3)

        promotions = tester.get_visible_promotions()
        results[country] = {
            "promotions_displayed": len(promotions),
            "currency_correct": all(
                p["currency"] == get_expected_currency(country)
                for p in promotions if "currency" in p
            ),
            "language_appropriate": all(
                is_language_appropriate(p["text"], country)
                for p in promotions
            ),
            "voucher_codes_present": any(
                p.get("voucher_code") for p in promotions
            ),
            "sample_promotions": promotions[:3]
        }

    return results

5. Performance Testing Under Mobile Conditions

Test app performance under realistic mobile network conditions:

def test_network_performance(tester, country="SG"):
    """Test app performance through mobile proxy."""
    tester.configure_proxy(country)

    metrics = {
        "app_launch_time": None,
        "restaurant_list_load": None,
        "menu_load_time": None,
        "search_response_time": None,
        "image_load_time": None
    }

    # Measure app launch
    start = time.time()
    tester.launch_app()
    tester.wait_for_home_screen()
    metrics["app_launch_time"] = round(time.time() - start, 2)

    # Measure restaurant list load
    start = time.time()
    tester.navigate_to_restaurants()
    tester.wait_for_restaurant_list()
    metrics["restaurant_list_load"] = round(time.time() - start, 2)

    # Measure menu load
    start = time.time()
    tester.tap_first_restaurant()
    tester.wait_for_menu()
    metrics["menu_load_time"] = round(time.time() - start, 2)

    # Measure search
    start = time.time()
    tester.search("chicken rice")
    tester.wait_for_search_results()
    metrics["search_response_time"] = round(time.time() - start, 2)

    return metrics

Automated Test Suite Architecture

CI/CD Integration

Integrate mobile proxy testing into your deployment pipeline:

# .github/workflows/mobile-testing.yml
name: Food Delivery App - Geo Testing

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  geo-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        country: [SG, MY, TH, PH, ID]
        platform: [android, ios]

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: pip install appium-python-client requests

      - name: Run geo-targeted tests
        env:
          PROXY_USER: ${{ secrets.DRT_PROXY_USER }}
          PROXY_PASS: ${{ secrets.DRT_PROXY_PASS }}
          TARGET_COUNTRY: ${{ matrix.country }}
          TARGET_PLATFORM: ${{ matrix.platform }}
        run: python tests/run_geo_tests.py

      - name: Upload test results
        uses: actions/upload-artifact@v4
        with:
          name: test-results-${{ matrix.country }}-${{ matrix.platform }}
          path: test-results/

Test Reporting

def generate_test_report(all_results):
    """Generate a comprehensive test report."""
    report = {
        "timestamp": datetime.utcnow().isoformat(),
        "summary": {
            "total_tests": 0,
            "passed": 0,
            "failed": 0,
            "countries_tested": [],
            "platforms_tested": []
        },
        "by_country": {},
        "failures": []
    }

    for country, country_results in all_results.items():
        report["summary"]["countries_tested"].append(country)
        country_pass = 0
        country_fail = 0

        for test_name, result in country_results.items():
            report["summary"]["total_tests"] += 1
            if result.get("passed", False):
                report["summary"]["passed"] += 1
                country_pass += 1
            else:
                report["summary"]["failed"] += 1
                country_fail += 1
                report["failures"].append({
                    "country": country,
                    "test": test_name,
                    "details": result
                })

        report["by_country"][country] = {
            "passed": country_pass,
            "failed": country_fail,
            "pass_rate": f"{country_pass / (country_pass + country_fail) * 100:.1f}%"
        }

    report["summary"]["pass_rate"] = f"{report['summary']['passed'] / report['summary']['total_tests'] * 100:.1f}%"

    return report

Best Practices

1. Test with Real Carrier IPs

Always use mobile proxies that provide real carrier IPs, not just residential IPs tagged as mobile. DataResearchTools mobile proxies connect through actual mobile carriers in each SEA country, ensuring your tests reflect real user conditions.

2. Test Across Carriers

Different carriers may produce different app behaviors. Test with multiple carriers per country when possible:

  • Singapore: Singtel, StarHub, M1
  • Malaysia: Maxis, Celcom, Digi
  • Thailand: AIS, DTAC, TrueMove
  • Philippines: Globe, Smart, DITO
  • Indonesia: Telkomsel, Indosat, XL

3. Schedule Regular Regression Tests

Run geo-targeted tests on a regular schedule, not just during development. Platform APIs and behaviors change frequently.

4. Document Country-Specific Behaviors

Maintain a reference document of expected behaviors per country to validate against during testing.

Conclusion

Mobile proxies transform food delivery app testing by providing authentic mobile network access across Southeast Asian markets. Instead of maintaining expensive device farms with local SIM cards, teams can use DataResearchTools mobile proxies to test geo-targeting, pricing, promotions, and app behavior from any location.

By integrating mobile proxy testing into your CI/CD pipeline, you can catch geo-specific issues before they reach users, ensuring a consistent experience across all your target markets in Southeast Asia.


Related Reading

Scroll to Top