2017-08-30 54 views
15

Mam wymaganie takie, że:Java: wywołać metodę z nazwą zapisaną w zmiennej

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`. 

tak, to czy jest coś możliwe jak:

driver.findElement(By.id("id1")).<something to call click()> 

już spojrzał na odbicie w Javie , ale to wyglądało na skomplikowane zgodnie z moim wymaganiem. Wszelkie wskazówki będą pomocne!

Odpowiedz

10

Najprostszym sposobem, aby to zrobić jest użycie refleksji.

String command = "click"; 
WebElement element = driver.findElement(By.id("id1")); 

Method method = WebElement.class.getMethod(command); 
method.invoke(element); 

Jeśli również chcesz zadzwonić By.id z refleksji, to można to zrobić:

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

Bardzo mi przykro, ponieważ zadaję kolejne pytanie w tym samym pytaniu. Co zrobić, jeśli mój "identyfikator" jest również zapisany w zmiennej. Na przykład: zmienna zawierająca 'id' lub' xpath', na podstawie której muszę wykonać operację: 'driver.findElement (przez. (" id1 ")). ' W tej sytuacji, w jaki sposób można rozszerzyć swoje rozwiązanie? –

+0

@OmSao Zmieniłem trochę kod i dodałem dla ciebie odpowiedź na drugie pytanie. Proszę mi powiedzieć, czy ten kod działa, ponieważ go nie testowałem. –

23

Twoja zmienna reprezentuje coś, co chcesz zrobić z elementem internetowym (w tym przypadku kliknij na niego).

Odpowiednim typem nie jest String. Użyj Consumer<WebElement> zamiast (lub bez względu na rodzaj jakich driver.findElement() zwrotów jest):

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

// ... 

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

Jest to typ bezpieczny, skuteczny, refactorable i znacznie bardziej elastyczna niż odbicia (ponieważ Twój konsument może robić, co chce z Element, nie ogranicza się do pojedynczego wywołania metody bez żadnego argumentu jak na przykład wpisać jakiś tekst w polu tekstowym)

+4

dobry punkt, nie może być 'Map ' aby pobrać potrzebne konsumentowi przez nazwę polecenia – Andrew

+0

Hi JB: Tak, jak na ciebie, muszę mention'click' podczas przypisywania 'Konsumenta '? Jeśli chcę wywoływać polecenia typu 'clear',' getLocation' itd., To znowu muszę zdefiniować explicity jak 'Consumer command = e -> e.clear();' Mam rację, lub jestem czegoś brakuje? –

+1

Tak. Tak jak musiałbyś zmienić 'String command =" click ";' na 'String command =" clear ";'. Poza tym, że na pewno użyjesz istniejącej metody, twoje IDE zapewni automatyczne uzupełnianie, możesz przekazać argumenty (np. 'Consumer command = e -> e.sendKeys (" hello ");'). –

6

W zakresie projektowania (i prawdopodobnie to może być dodatkowo zoptymalizowany i wydobywane na pewno), prawdopodobnie można zdefiniować Enum, nazwijmy go Action jak:

public enum Action { 
CLICK, 
SENDKEY, 
etc 
} 

W kodzie wtedy zrobić:

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

Wydaje się, starasz się zbudować ramy kluczowego napędzane. Szczerze mówiąc, byłbym bardzo zaskoczony, słysząc jakąś udaną historię na ten temat. Czy zawsze zastanawiałeś się, jaki jest prawdziwy cel tego rodzaju ram? Kto z niego skorzysta? Menedżerowie, manualne kontrole jakości lub interesariusze? Dla mnie nie ma sensu angażować osób nietechnicznych w czynności automatyzacji testów. Każda automatyzacja wymaga dobrych umiejętności technicznych (w tym programowanie i tworzenie aplikacji). W przeciwnym razie prawdopodobieństwo niepowodzenia jest dość wysokie.

W każdym razie twoje pytanie dotyczy bardziej mapowania strings vs functional interfaces lub bardzo inteligentnego użycia refleksji. Ale głównym problemem jest to, że wybrałeś złe API [input] dla tego. Następujący wiersz:

driver.findElement(locator).doSmth(); 

jest właściwa droga, by upaść, jak findElement wykorzystuje ukryte czeka. I jestem w 100% pewien, że zaczniesz globalne refaktoryzowanie/rewizję wdrożonego podejścia, gdy natkniesz się na NoSuchElementException/StaleElementReferenceException.

Zdrowy rozsądek sugeruje używanie płynnego czekania z ExpectedConditions. Ale to sprawi, że twoje zadanie będzie jeszcze bardziej skomplikowane, ponieważ oprócz lokalizatorów i działań musisz myśleć o warunkach, które powinny być dostarczane przez użytkowników.

Najpierw utworzę typowe opakowania, aby zamknąć wywołania interfejsu API WebDriver niskiego poziomu.Znacznie łatwiej byłoby odwzorować lub odzwierciedlić takie funkcje w porównaniu z nieprzetworzonymi połączeniami. Na przykład. spodziewane warunki mogą być ukryte na poziomie enum:

@Getter 
@RequiredArgsConstructor 
public enum WaitCondition { 

    visible(ExpectedConditions::visibilityOfElementLocated), 
    enabled(ExpectedConditions::elementToBeClickable); 

    private final Function<By, ExpectedCondition<WebElement>> type; 
} 

Łatwo będzie odzyskać wymaganą stałą, dzwoniąc np. WaitCondition.valueOf("visible"), gdzie ciąg wejściowy może być przekazywany z zewnątrz.

Wspólny interfejs API owijka może wyglądać następująco, a następnie: Przykłady

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)); 
} 

przekształcenia/odbicie już dostarczone przez innych, w tym nici. Uwaga: jeśli wolisz refleksję, polecam przejrzeć bibliotekę jOOR, co upraszcza ten proces.