HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

DRYing out some Java code and tests

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
dryingandtestsjavasomecodeout

Problem

I am writing some tests that all follow the same pattern, I feel like repeating myself over and over again, how can I reduce the repetition? The (almost) repeating part is in constructor and the class level variables:

VariablesPage

public class VariablesPage extends LoadableComponent {

    private final TestHelpers helpers;
    private WebDriver driver;

    @FindBy(xpath = "//a[@title=\"Define new variable\"]") 
    private WebElement btnAddNewVariable;

    public VariablesPage() throws Exception {
        helpers = new TestHelpers();
        driver = helpers.getWebDriver();
        helpers.setHar(VariablesPage.class.getSimpleName());
        PageFactory.initElements(driver, this);
        isLoaded();
        helpers.getHar();
    }

    @Override
    protected void load() {

    }

    @Override
    protected void isLoaded() throws Error {
        helpers.waitUntil(btnAddNewVariable);
    }
}


addStepsPage

public class AddStepsPage extends LoadableComponent {

    private final TestHelpers helpers;
    private WebDriver driver;
    @FindBy(xpath = "//div[@class=\"body sequential\"]")
    private WebElement divStepsBody;

    public AddStepsPage() throws Exception {
        helpers = new TestHelpers();
        driver = helpers.getWebDriver();
        helpers.setHar(AddStepsPage.class.getSimpleName());
        PageFactory.initElements(driver, this);
        isLoaded();
        helpers.getHar();
    }

    @Override
    protected void load() {

    }

    @Override
    protected void isLoaded() throws Error {
        helpers.waitUntil(divStepsBody);
    }
}

Solution

First, let us collect the code pieces which are repeated

Fields

private final TestHelpers helpers;
private WebDriver driver;


Constructor related

helpers = new TestHelpers();  
driver = helpers.getWebDriver();


Now, let's start refactoring by extending LoadableComponent

public abstract class ExtendedLoadableComponent extends LoadableComponent {

    protected final TestHelpers helpers
    protected WebDriver driver;

    public ExtendedLoadableComponent() throws Exception {
        helpers = new TestHelpers();
        driver = helpers.getWebDriver();
    }
}


which reduces the first class to

public class VariablesPage extends ExtendedLoadableComponent {

    @FindBy(xpath = "//a[@title=\"Define new variable\"]") 
    private WebElement btnAddNewVariable;

    public VariablesPage() throws Exception {
        super();
        helpers.setHar(VariablesPage.class.getSimpleName());
        PageFactory.initElements(driver, this);
        isLoaded();
        helpers.getHar();
    }

    @Override
    protected void load() {}

    @Override
    protected void isLoaded() throws Error {
        helpers.waitUntil(btnAddNewVariable);
    }
}


But wait, we can do better! So, let us also call helpers.setHar(String) and thus we need to refactor the constructor of ExtendedLoadableComponent

public abstract class ExtendedLoadableComponent extends LoadableComponent {

    protected final TestHelpers helpers
    protected WebDriver driver;

    public ExtendedLoadableComponent(Class pageClassToProxy) throws Exception {
        helpers = new TestHelpers();
        driver = helpers.getWebDriver();
        helpers.setHar(pageClassToProxy.getSimpleName());
        PageFactory.initElements(driver, pageClassToProxy);
    }
}


which reduces the first class to

public class VariablesPage extends ExtendedLoadableComponent {

    @FindBy(xpath = "//a[@title=\"Define new variable\"]") 
    private WebElement btnAddNewVariable;

    public VariablesPage() throws Exception {
        super(VariablesPage.class);
        isLoaded();
        helpers.getHar();
    }

    @Override
    protected void load() {}

    @Override
    protected void isLoaded() throws Error {
        helpers.waitUntil(btnAddNewVariable);
    }
}


Naming

I don't know if the TestHelpers class is your own. If yes, you should think about changing the names for setHar() and getHar() so Mr. Maintainer can evaluate what they do by looking at the names.

Code Snippets

private final TestHelpers helpers;
private WebDriver driver;
helpers = new TestHelpers();  
driver = helpers.getWebDriver();
public abstract class ExtendedLoadableComponent<T> extends LoadableComponent<T> {

    protected final TestHelpers helpers
    protected WebDriver driver;

    public ExtendedLoadableComponent() throws Exception {
        helpers = new TestHelpers();
        driver = helpers.getWebDriver();
    }
}
public class VariablesPage extends ExtendedLoadableComponent<VariablesPage> {

    @FindBy(xpath = "//a[@title=\"Define new variable\"]") 
    private WebElement btnAddNewVariable;

    public VariablesPage() throws Exception {
        super();
        helpers.setHar(VariablesPage.class.getSimpleName());
        PageFactory.initElements(driver, this);
        isLoaded();
        helpers.getHar();
    }

    @Override
    protected void load() {}

    @Override
    protected void isLoaded() throws Error {
        helpers.waitUntil(btnAddNewVariable);
    }
}
public abstract class ExtendedLoadableComponent<T> extends LoadableComponent<T> {

    protected final TestHelpers helpers
    protected WebDriver driver;

    public ExtendedLoadableComponent(Class<T> pageClassToProxy) throws Exception {
        helpers = new TestHelpers();
        driver = helpers.getWebDriver();
        helpers.setHar(pageClassToProxy.getSimpleName());
        PageFactory.initElements(driver, pageClassToProxy);
    }
}

Context

StackExchange Code Review Q#59388, answer score: 10

Revisions (0)

No revisions yet.