如何测试来自不同国家/地区的网络应用程序的页面加载时间?

How to test page load times of a web app from different countries?

我工作的公司有一个位于北美数据中心的网站,我想测试我们网站在不同大陆(特别是欧洲、亚洲和大洋洲)的页面加载时间。

我该怎么做?我不认识任何住在这些地区的人。

我希望能够使用 selenium 来自动执行此任务并执行各种操作,但这是一个很好的选择。

编辑:我想使用 Selenium 进行测试的原因是我可以从每个位置重复测试数百次,并获得我的应用程序页面的平均响应时间。我知道这些结果会有点模糊,但我主要是在寻找全局 - 例如,从欧洲加载页面 X 的时间是从亚洲加载页面 X 的两倍。

编辑 2:有人向我指出 Google Analytics 可用于按区域获取此类数据,这很有用,但帮助不大。它能很好地帮助我确定全局,但在帮助我了解我所做的更改如何影响加载时间方面却很慢,而这正是我真正想要的 - 在自动化下可以 运行 的东西。

我的网络驱动程序提供者界面:

package org.gk.networking;

public interface WebDriverProvider
{
    WebDriver requestWebDriver(WebDriverInitialization aInitialization)
            throws IllegalArgumentException,
            WebDriverProviderException;
}

抽象实现:

package org.gk.networking;

import java.util.List;
import java.util.Set;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver.Navigation;
import org.openqa.selenium.WebDriver.Options;
import org.openqa.selenium.WebDriver.TargetLocator;
import org.openqa.selenium.WebElement;

public abstract class AbstractWebDriver implements WebDriver
{
    AbstractWebDriver(org.openqa.selenium.WebDriver aWebDriver)
            throws IllegalArgumentException
    {
        if(aWebDriver == null)
        {
            throw new IllegalArgumentException("aWebDriver may not be null");
        }

        this.mWebDriver = aWebDriver;
    }

    @Override
    public void close()
            throws Exception
    {
        this.mWebDriver.quit();
    }

    @Override
    public final WebElement findElement(By aBy)
    {
        return this.mWebDriver.findElement(aBy);
    }

    @Override
    public final List<WebElement> findElements(By aBy)
    {
        return this.mWebDriver.findElements(aBy);
    }

    @Override
    public final void get(String aUrl)
    {
        this.mWebDriver.get(aUrl);
    }

    @Override
    public final String getCurrentUrl()
    {
        return this.mWebDriver.getCurrentUrl();
    }

    @Override
    public final String getPageSource()
    {
        return this.mWebDriver.getPageSource();
    }

    @Override
    public final String getTitle()
    {
        return this.mWebDriver.getTitle();
    }

    @Override
    public final String getWindowHandle()
    {
        return this.mWebDriver.getWindowHandle();
    }

    @Override
    public final Set<String> getWindowHandles()
    {
        return this.mWebDriver.getWindowHandles();
    }

    @Override
    public final Options manage()
    {
        return this.mWebDriver.manage();
    }

    @Override
    public final Navigation navigate()
    {
        return this.mWebDriver.navigate();
    }

    @Override
    public final void quit()
    {
        this.mWebDriver.quit();
    }

    @Override
    public final TargetLocator switchTo()
    {
        return this.mWebDriver.switchTo();
    }

    @Override
    public void webDriverClose()
    {
        this.mWebDriver.close();
    }

    @Override
    public final org.openqa.selenium.WebDriver getWebDriver()
    {
        return this.mWebDriver;
    }

    private final org.openqa.selenium.WebDriver mWebDriver;
}

Webdriver 接口,因为它不能自动关闭,我无法扩展原始接口,因为它已经有一个关闭方法。

package org.gk.networking;

import java.util.List;
import java.util.Set;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WebDriver.Navigation;
import org.openqa.selenium.WebDriver.Options;
import org.openqa.selenium.WebDriver.TargetLocator;

public interface WebDriver extends AutoCloseable
{
    WebElement findElement(By aBy);

    List<WebElement> findElements(By aBy);

    void get(String aUrl);

    String getCurrentUrl();

    String getPageSource();

    String getTitle();

    String getWindowHandle();

    Set<String> getWindowHandles();

    Options manage();

    Navigation navigate();

    void quit();

    TargetLocator switchTo();

    void webDriverClose();

    org.openqa.selenium.WebDriver getWebDriver();
}

Tor 网络驱动程序实现: 包裹 org.gk.networking;

import org.openqa.selenium.firefox.FirefoxDriver;

public class TorWebDriver extends AbstractWebDriver
{
    public TorWebDriver(FirefoxDriver aWebDriver)
            throws IllegalArgumentException
    {
        super(aWebDriver);
    }
}

Webdriver初始化界面: 包裹 org.gk.networking;

import org.openqa.selenium.remote.DesiredCapabilities;

public interface WebDriverInitialization
{
    DesiredCapabilities getCapabilities();
}

Tor webdriver初始化实现: 包裹 org.gk.networking;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.remote.DesiredCapabilities;

public class TorWebDriverInitialization implements WebDriverInitialization
{
    public TorWebDriverInitialization(DesiredCapabilities aCapabilities, FirefoxProfile aProfile,
            Collection<String> aCommandLineArguments)
                    throws IllegalArgumentException
    {
        if(aCapabilities == null)
        {
            throw new IllegalArgumentException("aCapabilities may not be null");
        }
        else if(aProfile == null)
        {
            throw new IllegalArgumentException("aProfile may not be null");
        }

        this.mCapabilities = aCapabilities;
        this.mProfile = aProfile;
        this.mCommandLineArguments = (aCommandLineArguments == null ? null : new ArrayList<>(aCommandLineArguments));
    }

    public TorWebDriverInitialization(FirefoxProfile aProfile)
            throws IllegalArgumentException
    {
        this(new DesiredCapabilities(), aProfile, null);
    }

    public TorWebDriverInitialization()
            throws IllegalArgumentException,
            UnsupportedEncodingException,
            FileNotFoundException
    {
        this(new DesiredCapabilities(), new FirefoxProfile(getDefaultProfileFile()), null);
    }

    @Override
    public DesiredCapabilities getCapabilities()
    {
        return this.mCapabilities;
    }

    public FirefoxProfile getProfile()
    {
        return this.mProfile;
    }

    public Collection<String> getCommandLineArguments()
    {
        if(this.mCommandLineArguments == null)
        {
            return null;
        }
        else
        {
            return Collections.unmodifiableCollection(this.mCommandLineArguments);
        }
    }

    public static synchronized File getDefaultProfileFile()
            throws UnsupportedEncodingException,
            FileNotFoundException
    {
        if(TOR_PROFILE_FILE != null)
        {
            return TOR_PROFILE_FILE;
        }

        String torProfilePath = "browsers/tor/profile.default";

        URL resource = TorWebDriverInitialization.class.getClassLoader().getResource(torProfilePath);
        if(resource == null)
        {
            throw new FileNotFoundException("Unable to open " + torProfilePath);
        }

        TOR_PROFILE_FILE = new File(URLDecoder.decode(resource.getFile(), "UTF-8"));

        return TOR_PROFILE_FILE;
    }

    private final DesiredCapabilities   mCapabilities;
    private final FirefoxProfile        mProfile;
    private final Collection<String>    mCommandLineArguments;

    private static File                 TOR_PROFILE_FILE;
}

最后,tor webdriver 提供程序实现: 包裹 org.gk.networking;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Collection;

import org.apache.commons.lang3.SystemUtils;
import org.gk.PlatformNotSupportedException;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Point;
import org.openqa.selenium.firefox.FirefoxBinary;
import org.openqa.selenium.firefox.FirefoxDriver;

public class TorWebDriverProvider implements WebDriverProvider
{
    public TorWebDriverProvider()
            throws FileNotFoundException,
            UnsupportedEncodingException,
            PlatformNotSupportedException
    {
        getTorBinaryFile();
    }

    @Override
    public WebDriver requestWebDriver(WebDriverInitialization aInitialization)
            throws IllegalArgumentException,
            WebDriverProviderException
    {
        if(aInitialization == null)
        {
            throw new IllegalArgumentException("aInitialization may not be null");
        }
        else if(!(aInitialization instanceof TorWebDriverInitialization))
        {
            throw new IllegalArgumentException("aInitialization must be of type TorPhantomJSWebDriverInitialization");
        }

        TorWebDriverInitialization initialization = (TorWebDriverInitialization)aInitialization;

        FirefoxBinary binary = null;
        FirefoxDriver rawWebDriver = null;
        try
        {
            binary = new FirefoxBinary(getTorBinaryFile());

            Collection<String> commandLineArguments = initialization.getCommandLineArguments();     
            if(commandLineArguments != null)
            {
                for(String argument : commandLineArguments)
                {
                    binary.addCommandLineOptions(argument);
                }
            }

            rawWebDriver = new FirefoxDriver(binary, initialization.getProfile(), initialization.getCapabilities());

            // Cheaty way to hide window
            //rawWebDriver.manage().window().setSize(new Dimension(0, 0));
            //rawWebDriver.manage().window().setPosition(new Point(-4000, 0));

            return new TorWebDriver(rawWebDriver);
        }
        catch(Throwable t)
        {
            try
            {
                if(rawWebDriver != null)
                {
                    rawWebDriver.quit();
                }
            }
            catch(Throwable t2)
            {
                t.addSuppressed(t2);
            }

            try
            {
                if(binary != null)
                {
                    binary.quit();
                }
            }
            catch(Throwable t2)
            {
                t.addSuppressed(t2);
            }

            throw new WebDriverProviderException(t);
        }
    }

    public static synchronized File getTorBinaryFile()
            throws PlatformNotSupportedException,
            FileNotFoundException,
            UnsupportedEncodingException
    {
        if(TOR_BINARY_FILE != null)
        {
            return TOR_BINARY_FILE;
        }

        String torBinaryFilePath;
        if(SystemUtils.IS_OS_WINDOWS)
        {
            if(SystemUtils.IS_OS_WINDOWS_NT || SystemUtils.IS_OS_WINDOWS_95 || SystemUtils.IS_OS_WINDOWS_98
                    || SystemUtils.IS_OS_WINDOWS_ME || SystemUtils.IS_OS_WINDOWS_2000)
            {
                throw new PlatformNotSupportedException("Minimum Windows version required is XP");
            }

            torBinaryFilePath = "browsers/tor/windows/tor_windows32/firefox.exe";
        }
        else if(SystemUtils.IS_OS_MAC_OSX)
        {
            if(SystemUtils.IS_OS_MAC_OSX_CHEETAH || SystemUtils.IS_OS_MAC_OSX_PUMA || SystemUtils.IS_OS_MAC_OSX_JAGUAR
                    || SystemUtils.IS_OS_MAC_OSX_PANTHER || SystemUtils.IS_OS_MAC_OSX_TIGER
                    || SystemUtils.IS_OS_MAC_OSX_LEOPARD)
            {
                throw new PlatformNotSupportedException("Minimum OSX version required is Snow Leopard");
            }

            torBinaryFilePath = "browsers/tor/osx/tor_osx64.dmg";
        }
        else if(SystemUtils.IS_OS_LINUX)
        {
            String architecture = SystemUtils.OS_ARCH;
            if(architecture == null)
            {
                throw new SecurityException("No permissions to read system property os.arch");
            }

            if(architecture.contains("64"))
            {
                torBinaryFilePath = "browsers/tor/linux/tor_linux32/firefox";
            }
            else
            {
                torBinaryFilePath = "browsers/tor/linux/tor_linux64/firefox";
            }
        }
        else
        {
            throw new PlatformNotSupportedException("The current platform is not supported");
        }

        URL resource = TorWebDriverProvider.class.getClassLoader().getResource(torBinaryFilePath);
        if(resource == null)
        {
            throw new FileNotFoundException("Unable to open " + torBinaryFilePath);
        }

        TOR_BINARY_FILE = new File(URLDecoder.decode(resource.getFile(), "UTF-8"));

        return TOR_BINARY_FILE;
    }

    private static File TOR_BINARY_FILE;
}

希望对你有用。

编辑: 顺便说一句,配置文件是一个随 Tor 浏览器副本一起提供的文件夹。下载的时候搜索一下就可以了。二进制文件只是例如 firefox.exe on windows.

另一种可能的方法是使用带有 VPN 连接的 Sauce Labs,使用 "Sauce Connect"、