如何测试来自不同国家/地区的网络应用程序的页面加载时间?
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"、
我工作的公司有一个位于北美数据中心的网站,我想测试我们网站在不同大陆(特别是欧洲、亚洲和大洋洲)的页面加载时间。
我该怎么做?我不认识任何住在这些地区的人。
我希望能够使用 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"、