Java:调用名称存储在变量中的方法

时间:2017-08-30 11:33:32

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

4 个答案:

答案 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库,这样可以简化此过程。