2017-08-30 56 views
15

我有这样一个要求:的Java:调用具有名称的方法保存在变量

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 ,但根据我的要求,这看起来很复杂。任何指针都会有帮助!

回答

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); 
+0

我很抱歉,因为我在同一个问题中提出另一个问题。 如果我的'id'也存储在一个变量中怎么办?例如,一个包含'id'或'xpath'的变量我必须采取行动: 'driver.findElement(By。<来自变量值>(“id1”))。' 在这种情况下,您的解决方案如何扩展? –

+0

@OmSao我已经改变了一些代码,并为你添加了第二个问题的答案。请告诉我这段代码是否有效,因为我没有测试过它。 –

23

你的变量代表你想要用一个web元素做的事情(在这种情况下,点击它)。

适当的类型不是String。使用Consumer<WebElement>代替(或无论什么driver.findElement()返回类型为):

Consumer<WebElement> command = e -> e.click(); 

// ... 

command.accept(driver.findElement(By.id("id1"))); 

这是类型安全,高效,refactorable,并远远超过反射更灵活(因为你的消费者可以为所欲为用元素,而不是局限于单一的方法调用不带任何参数例如像,请在文本字段中某些文本)

+4

好点,有可能是一个'地图<字符串,消费者'通过一个命令名称 – Andrew

+0

JB喜取一个需要消费者:那么,按照你的,我有消费者的'分配期间mention'click' '? 如果我想调用类似'clear','getLocation'等命令,那么我必须再次定义明确性,如 'Consumer command = e - > e.clear();' 我是对的还是我遗漏了什么 ? –

+1

是的。就像你不得不将'String command =“click”;'改成'String command =“clear”;'一样。除了确保实际使用存在的方法之外,IDE将提供自动完成功能,您可以传递参数(即'Consumer command = e - > e.sendKeys(“hello”);')。 –

6

在设计方面(也许这可以进一步优化和抽象肯定的),你也许可以定义一个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; 
} 
0

好像你正在试图建立一个关键字驱动的框架。说实话,听到这个成功的故事,我会感到非常惊讶。总是想知道这种框架的真正目的是什么?谁会用它?经理,手动QA或利益相关者?对我来说,让非技术人员参与测试自动化活动是没有意义的。任何自动化都需要良好的技术技能(包括编程和devops)。否则,失败概率相当高。

无论如何,你的问题是更多关于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"),其中输入字符串可以从外部传递。

通用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库,这可以简化此过程。

相关问题