2012-04-25 32 views
9

Pregunta rápida sobre objetos de página en selenium webdriver. nuestro sitio es muy dinámico con muchos ajax y varios estados de autenticación. Es difícil encontrar la forma de definir cada objeto de página, PERO digamos que lo he descubierto y definido varios objetos de página que representan nuestro sitio.Selenium WebDriver objeto de página

¿Cómo se maneja el cruce de una página a otra? Así que obtengo un objeto de página para mi página de inicio y uno para mi página de cuenta y otro para mi página de resultados. Luego, tengo que escribir una prueba que atraviese todas mis páginas para simular un usuario que realiza múltiples acciones.

Como dice darme un objeto HomePage para crear un nuevo uso -> luego obtener un objeto de página de cuenta para realizar algunas acciones del usuario - luego obtener un objeto de página de resultados para verificar esas acciones desde un solo script.

¿Cómo están haciendo esto las personas?

gracias

+0

¿Qué quiere decir exactamente con "objeto de página"? – Alp

Respuesta

10

Cuando se está simulando que el usuario introduzca un nuevo URL en la barra de URL del navegador, entonces es responsabilidad de la clase de prueba crear el objeto de página que necesita.

Por otro lado, cuando realiza alguna operación en la página que haría que el navegador señale a otra página, por ejemplo, haciendo clic en un enlace o enviando un formulario, entonces es responsabilidad de esa página objeto para devolver el objeto de la página siguiente.

Dado que no sé lo suficiente sobre las relaciones entre su página de inicio, página de cuenta y página de resultados para decirle exactamente cómo se desarrollaría en su sitio, utilizaré una aplicación de tienda en línea como ejemplo en lugar.

Digamos que tienes una página de búsqueda. Cuando envía el formulario en la página de búsqueda, devuelve una página de resultados. Y cuando haces clic en un resultado, obtienes una ProductPage. Por lo que las clases se vería algo como esto (abreviado a sólo los métodos pertinentes):

public class SearchPage { 

    public void open() { 
     return driver.get(url); 
    } 

    public ResultsPage search(String term) { 
     // Code to enter the term into the search box goes here 
     // Code to click the submit button goes here 
     return new ResultsPage(); 
    } 

} 

public class ResultsPage { 

    public ProductPage openResult(int resultNumber) { 
     // Code to locate the relevant result link and click on it 
     return new ProductPage(); 
    } 

} 

El método de prueba para ejecutar esta historia sería algo como esto:

@Test 
public void testSearch() { 

    // Here we want to simulate the user going to the search page 
    // as if opening a browser and entering the URL in the address bar. 
    // So we instantiate it here in the test code. 

    SearchPage searchPage = new SearchPage(); 
    searchPage.open(); // calls driver.get() on the correct URL 

    // Now search for "video games" 

    ResultsPage videoGameResultsPage = searchPage.search("video games"); 

    // Now open the first result 

    ProductPage firstProductPage = videoGameResultsPage.openResult(0); 

    // Some assertion would probably go here 

} 

Así como se puede ver, existe este "encadenamiento" de Objetos de página donde cada uno devuelve el siguiente.

El resultado es que terminas con muchos objetos de página diferentes creando instancias de otros objetos de página. Entonces, si tiene un sitio de un tamaño considerable, podría considerar usar un marco de inyección de dependencia para crear esos objetos de página.

+0

Esto es lo que pensé que necesitaba hacer. parece un poco torpe ya que nuestro sitio es muy ajaxy y las acciones en el sitio vuelven a diferentes lugares dependiendo de en qué estado se encuentre actualmente el usuario. – ducati1212

+0

El problema con este código es que cada página necesita llamar a PageFactory.initObjects() y la instancia del controlador no puede inicializar todos los objetos en 2 páginas diferentes (digamos que son 2 ventanas diferentes o un marco incrustado). Entonces, aunque estoy de acuerdo en que este es un gran patrón de diseño para muchas cosas, este patrón se descompone rápidamente y solo funciona para ciertas aplicaciones. La forma en que está diseñado WebDriver PageFactory, es mucho mejor abrir un objeto de página, usarlo, marcarlo para la recolección de basura, luego instanciar la página siguiente, usarla, etc. Tal vez podría ampliar PageFactory, como una solución, tal vez. – djangofan

4

Bueno, he creado mis propias clases Java que representan las páginas:

digamos, el siguiente es el código para representar la página de inicio. Aquí el usuario puede iniciar sesión:

public class HomePage{ 
    private WebDriver driver; 
    private WebElement loginInput; 
    private WebElement passwordInput; 
    private WebElement loginSubmit; 

    public WebDriver getDriver(){ 
    return driver; 
    } 

    public HomePage(){ 
    driver = new FirefoxDriver(); 
    } 

    public CustomerPage login(String username, String password){ 
    driver.get("http://the-test-page.com"); 
    loginInput = driver.findElement(By.id("username")); 
    loginInput.sendKeys(username); 
    passwordInput = driver.findElement(By.id("password")); 
    passwordInput.sendKeys(password); 
    loginSubmit = driver.findElement(By.id("login")); 
    loginSubmit.click(); 
    return new CustomerPage(this); 
    } 


} 

Y la página para el cliente puede verse así. Aquí estoy demostrando, cómo llegar, por ejemplo, cerrar sesión de usuario:

public class CustomerPage{ 
    private HomePage homePage; 
    private WebElement loggedInUserSpan; 

public CustomerPage(HomePage hp){ 
    this.homePage = hp; 
    } 

public String getLoggedInUser(){ 
     loggedInUserSpan = homePage.getDriver().findElement(By.id("usrLongName")); 
     return loggedInUserSpan.getText(); 
} 

} 

Y la prueba puede ir así:

@Test 
public void testLogin(){ 
    HomePage home = new HomePage(); 
    CustomerPage customer = home.login("janipav", "extrasecretpassword"); 
    Assert.assertEquals(customer.getLoggedInUser(), "Pavel Janicek"); 
} 
1

Le sugiero que utilice un marco que proporcione soporte para estos patrones. Geb es uno de los mejores que hay.A continuación se muestra un ejemplo tomado de su manual de

Browser.drive { 
    to LoginPage 
    assert at(LoginPage) 
    loginForm.with { 
     username = "admin" 
     password = "password" 
    } 
    loginButton.click() 
    assert at(AdminPage) 
} 

class LoginPage extends Page { 
    static url = "http://myapp.com/login" 
    static at = { heading.text() == "Please Login" } 
    static content = { 
     heading { $("h1") } 
     loginForm { $("form.login") } 
     loginButton(to: AdminPage) { loginForm.login() } 
    } 
} 

class AdminPage extends Page { 
    static at = { heading.text() == "Admin Section" } 
    static content = { 
     heading { $("h1") } 
    } 
} 
2

Por lo general, desea modelar lo que un usuario realmente hace cuando usa su sitio. Esto termina adoptando la forma de un lenguaje específico de dominio (DSL) al usar objetos de página. Sin embargo, se confunde con los componentes de página reutilizables.

Ahora que Java 8 está fuera con los métodos predeterminados, los componentes reutilizables de la página se pueden tratar como mixins utilizando métodos predeterminados. Tengo una publicación de blog con algunos ejemplos de código que se encuentran aquí que explican esto con más detalle: http://blog.jsdevel.me/2015/04/pageobjects-done-right-in-java-8.html

Cuestiones relacionadas