我正在使用Jmeter和Java Sampler为网站运行Selenium测试。 我导出了测试类,它使用" Eclipse扩展AbstractJavaSamplerClient - >导出到jar"并将其复制到Jmeter / lib / ext。我在我的测试中使用了来自另一个java项目的类。我将这个项目打包到.jar并将其复制到Jmeter / lib。 当我在Jmeter的1个线程中运行我的测试时它工作得很好但是如果我运行2个或更多线程,Selenium web驱动程序无法找到元素,但我看到它们是可见的。我是新手,但看起来Selenium不能在多线程中工作。 我究竟做错了什么?请帮忙。
答案 0 :(得分:1)
根据How to Use JUnit With JMeter指南,某些限制适用于JMeter的JUnit采样器,以及
仅为JUnit请求采样器记录“已用时间”。您将无法看到Latency或Bytes指标,因为JMeter对您的JUnit测试一无所知。因此,JMeter只能测量您的测试方法执行时间
目前(根据JMeter 2.11)无法运行JUnit套件或夹具。每个JUnit Request Sampler实例只能执行单个测试用例并且只能执行一个测试用例
JUnit测试设计存在某些限制。由于JMeter的多线程特性,测试开发人员需要使用线程安全的方法(即尽可能避免使用静态字段和方法,并记住资源可能忙于另一个线程)。
< / LI>- 醇>
有限的JUnit请求采样器配置功能假设所有测试前和测试后的逻辑都应该采用setUp和tearDown方法。如果需要将外部数据提供给采样器,请使用属性文件或系统属性
你最有可能患上第3点。
此外,根据WebDriver Tutorial
注意:此项目的目的不是替换JMeter中包含的HTTP Samplers。相反,它意味着通过测量最终用户加载时间来补充它们。
此外,来自同一来源:
根据经验,读者创建的浏览器(线程)数量应受以下公式限制:
C = B + 1
其中C =运行测试的主机的核心数 和N =浏览器数(线程数)。 例如,如果当前读者的主机有4个核心,则该公式将产生:
4 = 3 + 1
意味着脚本应该具有3个线程的 MAXIMUM 。
因此我建议使用JMeter通过单独线程组中的1个线程中的JUnit Sampler生成主加载和WebDriver Sampler或现有代码,以测量实际用户体验。
答案 1 :(得分:0)
我遇到这个问题已经有一段时间了,没有什么,请说明你所有的变量没有“静态”关键词,它对我有用。
由于
答案 2 :(得分:0)
Dmitri T在他的回答中指出,当使用某些静态字段时,通过Jmerter进行的JUnit-Selenium测试的多胎次运行中断。 在我们的项目中,我们面临着与问题状态相同的症状,例如测试找不到元素,或者一个线程在其他人使用它时关闭了webdriver。
因此,我们实现了以下方法,该方法使我们的测试具有胎面安全性,并允许通过JMeter以多线程方式运行runnig。
首先,让我们提到Junit-Selenium测试中的静态对象通常使用@BeforeClass
方法出现,这些方法必须声明为静态并且可以使用静态字段。同样,您可能会使用@ClassRule
批注,该批注也必须放在静态字段中。但是,JMeter Junit Sampler不会处理@ClassRule
注释,因此我将不再赘述。
在我们的案例中,通过@BeforeClass
初始化,我们拥有TestBase
类,在该类中我们初始化了webdriver和一些其他资源以用于所有测试。我只是简化了真实的类以进行更清晰的演示:
public abstract class P01_SL_TestBase {
public static WebDriverResource driver = new FirefoxDriverResource();
public static PageProvider<ARMLoginPage> loginPageProvider;
public static ARMLoginPage loginPage;
public static ARMApplicationStartPage ARMPage;
@BeforeClass
public static void loadApplication () {
initResourcesForJmeterRunner();
loadARM (armUser);
}
public static void initResourcesForJmeterRunner() throws Throwable {
webDriverResource.before();
}
public static void loadARM(BPMUser armUser) {
loginPageProvider =
new PageProvider<ARMLoginPage>(ARMLoginPage.class,
BASE_URL_ADF_ARM_LOGIN_PAGE,
driver.getDriver()); //Here
//we get thread-local value of
//Firefox driver for our current thread
//from the threadwide storage
loginPage = loginPageProvider.goHome();
}
}
正如您在TestBase
中所见,静态字段驱动程序和其他一些常见情况。还有@BeforeClass
方法可做两件事。首先,实例化webdriver。其次,将要测试的应用程序初始化。因此,TestBase
类中的所有内容都与在一个线程或多线程中运行的测试无关。
我们在WebDriverResource
类中添加了多线程运行的实现:
public abstract class WebDriverResource extends ExternalResource {
// private final RemoteWebDriver driver; //this is implementation for
//one thread running,
//it is not thread-safety
/**
* {@code threadLocalDriverStorage} field stores thread-local instances
* of {@code RemoteWebDriver}.
* Note that now {@code threadLocalDriverStorage} is not static. We made
* this for backward compatibility of some
* existent tests using non-static createDriver() method.
* TODO refactor createDriver() declaration and implementation to static
* variant.
*/
private ThreadLocal<RemoteWebDriver> threadLocalDriverStorage =
new ThreadLocal<RemoteWebDriver>() {
@Override
protected RemoteWebDriver initialValue() {
return createDriver(locale.toLanguageTag());
}
};
public WebDriverResource() {
}
protected abstract RemoteWebDriver createDriver(String language);
@Override
public void before() throws Throwable {
//here we call threadLocalDriverStorage.get() first time,
//and so the get() will perform initialValue()
//and save to storage thread-local value for the current thread
threadLocalDriverStorage.get()
.manage()
.window()
.maximize();
}
@Override
protected void after() {
logger.fine("quit browser...");
//driver.quit();
threadLocalDriverStorage.get().close();
}
/**
* @return thread-local value of {@code RemoteWebDriver}
*/
public RemoteWebDriver getDriver() {
return threadLocalDriverStorage.get();
}
}
在这里,我们使用TreadLocal类来实现threadLocalDriverStorage
字段。我们重写initialValue()
方法以返回RemoteWebDriver
对象的实例。
然后在before()
方法中,当我们第一次调用TreadLocal.get()
时,它将导致调用initialValue()
方法并实例化当前线程的RemoteWebDriver
对象。
还有getDriver()
,它们返回RemoteWebDriver
的局部局部值。在所有测试类中都应使用此方法来获取驱动程序对象。
我们还将Webdriver字段存储在页面对象模型类中。因此,我们还将受保护的静态ThreadLocal<RemoteWebDriver> threadLocalDriverStorage
字段添加到我们的基类中。但是这里我们不重写initialValue()
方法。相反,我们使用TreadLocal.set()
方法为当前线程保存值。
public abstract class Page {
// private final RemoteWebDriver driver; //this is implementation for
//one thread running,
//is not thread-safety
/**
* {@threadLocalDriverStorage} field stores thread-local instances of
* {@RemoteWebDriver}.
*
* Note that {@threadLocalDriverStorage} must be static. Without that
* static classes extended Page will
* work with unpredictable instance of {@threadLocalDriverStorage} and
* as result would not set and get {@RemoteWebDriver} instance properly
*
* Note that {@ThreadLocal.initialValue()} method is not overrided.
* Therefore thread-local value must be stored by
* {@ThreadLocal.set()} method.
* We do that in class consractor.
*/
protected static ThreadLocal<RemoteWebDriver> threadLocalDriverStorage =
new ThreadLocal<RemoteWebDriver>();
public Page(WebDriver driver) {
super();
threadLocalDriverStorage.set((RemoteWebDriver)driver);
}
}