Java:调用名称存储在变量中的方法
我的要求如下:Java:调用名称存储在变量中的方法,java,selenium,Java,Selenium,我的要求如下: 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 "clic
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()>
driver.findElement(By.id(“id1”))。
我已经研究了Java中的反射,但根据我的要求,这看起来很复杂。任何提示都会有帮助 您的变量表示希望对web元素执行的操作(在本例中,单击它) 相应的类型不是
String
。使用消费者
(或driver.findElement()
返回的任何类型):
Consumer命令=e->e.点击();
// ...
command.accept(driver.findElement(By.id(“id1”));
这是类型安全、高效、可重构的,并且比反射灵活得多(因为您的使用者可以对元素执行任何它想要的操作,而不限于不带任何参数的单个方法调用。例如,在文本字段中输入一些文本)最简单的方法是使用反射:
String command = "click";
WebElement element = driver.findElement(By.id("id1"));
Method method = WebElement.class.getMethod(command);
method.invoke(element);
如果还希望通过.id调用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);
在设计方面(可能可以进一步优化和抽象),您可能可以定义一个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;
}
Action=;
//找到元素
WebElement=driver.findElement(By.id(“id1”));
开关(动作){
案例点击:
元素。单击();
打破
案例发送键:
元素sendKey();
打破
...
违约:
System.out.println(“未定义动作”);
打破
}
似乎您正在尝试构建一个关键字驱动的框架。老实说,我会非常惊讶地听到任何成功的故事。我一直想知道这种框架的真正目的是什么?谁会用它?管理者、手动质量保证机构或利益相关者?对我来说,让非技术人员参与测试自动化活动毫无意义。任何自动化都需要良好的技术技能(包括编程和devops)。否则,失效概率相当高
无论如何,您的问题更多的是关于字符串
与功能接口
映射,或者非常智能的反射用法。但主要的问题是,您为此选择了错误的API[输入]。以下一行:
driver.findElement(locator).doSmth();
是一种正确的失败方式,因为findElement
使用隐式等待。我100%确信,当您面对NoTouchElementException
/StaleElementReferenceException
时,您将开始全局重构/修改实现的方法
常识建议对ExpectedConditions
使用流畅的等待。但这会使您的任务更加复杂,因为除了定位器和操作之外,您还必须考虑用户应该提供的条件
从技术角度来看,我会首先创建公共包装器来封装低级WebDriver API调用。与原始调用相比,映射或反映这样的函数要容易得多。例如,可以在枚举级别隐藏预期条件:
@Getter
@RequiredArgsConstructor
public enum WaitCondition {
visible(ExpectedConditions::visibilityOfElementLocated),
enabled(ExpectedConditions::elementToBeClickable);
private final Function<By, ExpectedCondition<WebElement>> type;
}
本线程中的其他人已经提供了映射/反射示例。请注意:如果您喜欢反射,我建议您查看库,它简化了这个过程。好的一点,可能有一个
MapHi JB:所以,根据您的说法,我必须提到消费者
分配期间的点击
?如果我想调用像clear
,getLocation
等命令,那么我必须再次定义明确性,比如consumercommand=e->e.clear()代码>我是对的,还是我遗漏了什么?是的。就像您必须更改String command=“click”代码>插入String命令=“清除”代码>。除非您确实要使用现有的方法,否则您的IDE将提供自动完成功能,您可以传递参数(即Consumer command=e->e.sendKeys(“hello”);
)。关于第一部分:然后将您的命令解析为Consumer:即“click”解析为e->e.click()
,“text\u hello”例如,解析为e->e.sendKeys(“hello”)
。关于第二部分,使用一个包含消费者的对象和一个By
实例,允许查找要消费的元素。在某些情况下,甚至可以通过使用方法引用将其缩短一点,例如,Consumer command=WebElement::click;我真的很抱歉,因为我在同一个问题中又问了一个问题。如果我的id
也存储在变量中,该怎么办。例如,一个包含id
或xpath
的变量,我必须根据该变量采取行动:driver.findelelement(By.(“id1”)。
在这种情况下,如何扩展您的解决方案?@OmSao我对代码做了一些修改,并为您的第二个问题添加了答案。请告诉我这个代码是否有效,因为我还没有测试过它。
@Getter
@RequiredArgsConstructor
public enum WaitCondition {
visible(ExpectedConditions::visibilityOfElementLocated),
enabled(ExpectedConditions::elementToBeClickable);
private final Function<By, ExpectedCondition<WebElement>> type;
}
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));
}