The idea of utility class/capabilities (UFC) is a harmful one, as a result of they have a tendency to finish up breaking the Single Duty Precept, as they’ll have shoppers with fully totally different causes for altering the utility class/operate.
However we are able to lower the chance by decoupling the UFCs from its courses.
There are a number of methods:
1 – Dependency Injection
This fashion, you may simply change implementations of the UFCs:
public class ExampleClass {
non-public ultimate WaitHelper waitHelper;
public ExampleClass(WaitHelper waitHelper) {
this.waitHelper = waitHelper;
}
public void performAction() {
waitHelper.waitForElement();
}
}
interface WaitHelper {
void waitForElement();
}
public class DefaultWaitHelper implements WaitHelper {
public void waitForElement() {
// Implementation
}
}
2 – Manufacturing facility Strategies
If the constructions of the utilities is complicated, Manufacturing facility Strategies may help to isolate this complexity:
public class WaitHelperFactory {
public static WaitHelper createDefault() {
// Some complicated code right here
return new DefaultWaitHelper();
}
public static WaitHelper createWithCustomTimeout(TimeUnit unit, int worth) {
// Some complicated code right here
return new DefaultWaitHelper(unit, worth);
}
}
Then within the shoppers:
WaitHelper waitHelper = WaitHelperFactory.createDefault();
WaitHelper waitHelper = WaitHelperFactory.createWithCustomTimeout(TimeUnit.MINUTES, 1);
3 – Mixins
Interfaces with default habits may help to share capabilities between courses with out creating static dependencies between them.
public interface WaitHelper {
default void waitForElement() {
// Implementation
}
}
public class ExampleClass implements WaitHelper {
public void performAction() {
waitForElement(); // Methodology from the Interface, shared between all WaitHelper derivatives
}
}
4 – Context objects
If a number of UFCs come collectively, you may inject them as a context object:
@Getter
public class TestContext {
WaitHelper waitHelper;
SeleniumUtils seleniumUtils;
}
public class ExampleClass {
non-public ultimate TestContext context;
public ExampleClass(TestContext context) {
this.context = context;
}
public void performAction() {
context.getWaitHelper().waitForElement();
}
}
5 – Facet-Oriented Programming (AOP)
Cross-cutting considerations, e.g. logging, will be carried out with out creating dependencies utilizing AOP.
E.g.
As an example you’ve got this web page object class
public class LoginPage {
non-public WebDriver driver;
// Locators
non-public By usernameField = By.id("username");
non-public By passwordField = By.id("password");
non-public By loginButton = By.id("loginButton");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void enterUsername(String username) {
driver.findElement(usernameField).sendKeys(username);
}
public void enterPassword(String password) {
driver.findElement(passwordField).sendKeys(password);
}
public void clickLogin() {
driver.findElement(loginButton).click on();
}
}
You possibly can log the entries and exit outcomes of the usages of the strategies with an Facet like this:
@Facet
@Part
public class LoggingAspect {
non-public static ultimate Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// Pointcut to focus on strategies within the LoginPage class
@Pointcut("execution(* com.instance.pages.LoginPage.*(..))")
public void loginPageMethods() {}
// Log methodology entry
@Earlier than("loginPageMethods()")
public void logBefore(JoinPoint joinPoint) {
logger.data("Getting into methodology: {} with arguments: {}",
joinPoint.getSignature().getName(),
joinPoint.getArgs());
}
// Log profitable methodology execution
@AfterReturning(pointcut = "loginPageMethods()", returning = "consequence")
public void logAfterReturning(JoinPoint joinPoint, Object consequence) {
logger.data("Methodology executed efficiently: {} with consequence: {}",
joinPoint.getSignature().getName(),
consequence);
}
// Log exceptions thrown by strategies
@AfterThrowing(pointcut = "loginPageMethods()", throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
logger.error("Exception in methodology: {} with message: {}",
joinPoint.getSignature().getName(),
error.getMessage());
}
}