简体   繁体   中英

Mapping Selenium Annotation to Spring Bean

I am using Selenium to do some of my automation work. I am using Page Object Model(POM) based approach to define my WebElement property.

@FindBy(id = "username")
private WebElement usernameText;

@FindBy(css = "password")
private WebElement passwordText;

I do not want the annotation parameters(id=username and css=password) to be specified in the class directly.

Is it possible to move these to a bean properties file in Spring, so that I can map these annotations to a bean object.

For example, I can define a bean object to pass the id and css values, which should be auto-wired to this object in my Java class.

I don't actually see how it may be useful for you making WebElement instance ApplicationContext aware as WebElement has no Spring beans dependencies. Despite it lets have a look what we will have to do to achieve the goal:

  1. Each time WebElement is created by Selenium, BeanDefinition with prototype scope for this instance should be created as well and should be registered with a unique name in BeanDefinitionRegistry
  2. After BeanDefinition is created, corresponding WebElement instance should be created lazily inside ApplicationContext as this WebElement may be absent in DOM in the moment of its creation. Additionally on this stage we have to provide locator somehow
  3. As you will have a lot of WebElement s in a single Page Object, you will not be able to inject WebElement instance by type. Thus you will have to use @Qualifier or @Resource annotations on fields + @Lazy annotation for lazy bean initialization. It is at least 2 annotations on each WebElement field
  4. ...

Do you see how complicated it is?

From my perspective you do not need to put WebElement into ApplicationContext . Some things that may be useful:

  • In case Page Factory pattern usage implement BeanPostProcessor for your Page Objects and call PageFactory.initElements(..) from there. And that's it
  • Get rid of @FindBy annotations and use Page Object pattern only. You can store your locators as By objects in enum . It is handy to store such enum as nested class of particular Page Object or as separate class if you wish so. You may retrieve these By objects using WebElementFactory .

Example below:

public interface Labeled {
    String label();
}

public interface ByAware {
    By locator();
}

public interface WebElementDescriptor extends ByAware, Labeled {
}

@Component("pageObject")
public class PageObject {

    @Autowired
    private WebElementFactory factory;

    public PageObject login(String name, String password) {
        factory.getWebElement(Element.USERNAME_FIELD).sendKeys(name);
        factory.getWebElement(Element.PASSWORD_FIELD).sendKeys(password);
        return this;
    }

    enum Element implements WebElementDescriptor {
        USERNAME_FIELD(By.id("username"), "User name input field"),
        PASSWORD_FIELD(By.cssSelector("password"), "Password input field");

        private By by;

        private String label;

        Element(By by, String label) {
            this.by = by;
            this.label = label;
        }

        @Override
        public String label() {
            return label;
        }

        @Override
        public By locator() {
            return by;
        }

    }

}

@Component("webElementFactory")
public class WebElementFactory {

    @Autowired
    private WebDriver driver;

    public WebElement getWebElement(WebElementDescriptor descriptor) {
        System.out.println("Processing " + descriptor.label());
        return driver.findElementBy(descriptor.locator());
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM