我有一个要求:
String command = "click"; // this can have value such as clear, getLocation, getSize, getTagName etc.
WebDriver driver = new ChromeDriver(options); //creating a webdriver object
driver.findElement(By.id("id1")).click(); //Here I want "click" method should be called dynamically as per what I have stored in variable `command`.
那么,是否有可能像:
driver.findElement(By.id("id1")).<something to call click()>
我已经看过Java中的Reflection,但根据我的要求,这看起来很复杂。任何指针都会有所帮助!
答案 0 :(得分:23)
您的变量代表您要对Web元素执行的操作(在本例中,单击它)。
适合的类型不是String
。改为使用Consumer<WebElement>
(或driver.findElement()
返回的任何类型):
Consumer<WebElement> command = e -> e.click();
// ...
command.accept(driver.findElement(By.id("id1")));
这是类型安全,高效,可重构,并且比反射更灵活(因为您的消费者可以使用元素做任何他想做的事情,不限于没有任何参数的单个方法调用。例如,输入一些文本在文本字段中)
答案 1 :(得分:10)
最简单的方法是使用反射:
String command = "click";
WebElement element = driver.findElement(By.id("id1"));
Method method = WebElement.class.getMethod(command);
method.invoke(element);
如果您还想使用反射调用By.id
,那么您可以执行此操作:
String command = "click";
String id = "id";
Method byMethod = By.class.getMethod(id, String.class);
WebElement element = driver.findElement((By) byMethod.invoke(null, "id1"));
Method method = WebElement.class.getMethod(command);
method.invoke(element);
答案 2 :(得分:5)
在设计方面(可能这可以进一步优化和抽象),您可以定义Enum
,让我们将其命名为Action
:
public enum Action {
CLICK,
SENDKEY,
etc
}
在您的代码中,然后执行:
Action action = <input>;
// find the element
WebElement element = driver.findElement(By.id("id1"));
switch(action) {
case CLICK:
element.click();
break;
case SENDKEY:
element.sendKey();
break;
...
default:
System.out.println("Undefined action");
break;
}
答案 3 :(得分:0)
似乎您正在尝试构建关键字驱动的框架。说实话,听到任何成功的故事,我都会感到非常惊讶。总是想知道这种框架的真正目的是什么?谁会用它?经理,手工QA或利益相关者?对我而言,让非技术人员参与测试自动化活动是没有意义的。任何自动化都需要良好的技术技能(包括编程和开发)。否则,失败概率很高。
无论如何,您的问题更多地是关于strings
vs functional interfaces
映射,或非常智能的反射用法。但主要问题是您为此选择了错误的API [输入]。以下一行:
driver.findElement(locator).doSmth();
是一种正确的失败方式,因为findElement
使用隐式等待。当您面对NoSuchElementException
/ StaleElementReferenceException
时,我确信您将开始全局重构/修改已实施的方法。
常识建议使用ExpectedConditions
的流畅等待。但是它会使你的任务变得更加复杂,因为除了定位器和动作之外你还要考虑应该由用户提供的条件。
从技术角度来说,我首先创建公共包装器来封装低级WebDriver API调用。与原始调用相比,映射或反映此类函数要容易得多。例如。预期条件可能隐藏在枚举级别上:
@Getter
@RequiredArgsConstructor
public enum WaitCondition {
visible(ExpectedConditions::visibilityOfElementLocated),
enabled(ExpectedConditions::elementToBeClickable);
private final Function<By, ExpectedCondition<WebElement>> type;
}
通过调用例如,很容易检索所需的常量WaitCondition.valueOf("visible")
,其中输入字符串可以从外部传递。
Common API包装器可能如下所示:
protected void click(By locator) {
click(locator, enabled);
}
protected void click(By locator, WaitCondition condition) {
waitFor(locator, condition).click();
}
private WebElement waitFor(By locator, WaitCondition condition) {
return wait.until(condition.getType().apply(locator));
}
此线程中的其他人已经提供了映射/反射示例。请注意:如果您更喜欢反思,我建议您查看jOOR库,这样可以简化此过程。