2

Let's consider an example from WebDriver where I create two different classes to deal with page object, one stores the element locator and other actual operations dealing with page -

public class ContactPageElements  {
   private By nameTextBox = By.id("name");

   public static By getNameLocator() {
      return nameTextBox;
   }
}


public class ContactPage  {
  public ContactPage enterName(String name) {      
    findElement(ContactPageElements.getNameLocator()).sendKeys(name);
    return this;
  }
}

Now if I were to replace WebDriver with snazy new test framework then I would break the ContactPage class since it depends on By object being returned from ContactPageElements class.

Hence it appears to me that ContactPageElements class should not have a public method returning By object. But then what option am I left with?

I am hesitant to keep element locators in the ContactPage as I may end up violating single responsibility principle.

3

You are right to be hesitant in leaking your third party library types all over your own code.

You are also right in wanting to keep your classes focused and to the point.

The way you get around it is by hiding the third party library behind an "API" that you code and maintain yourself. You can do that by putting adapters and/or facade's to good use. Yes, it will mean extra code, essentially an extra "layer" that doesn't do much more than pass through to your third party library, but it does get you the best of both worlds.

As I said in a comment on Should I write an interface API before an implementation?:

Wrapping third party libraries isn't a YAGNI violation, but a much needed protection against "third party library infestation of your own code". It is not just about being able to swap out a library, but as MetaFight also says a defense against changes in newer versions of the library which would otherwise require changes throughout your own code. By wrapping the library (and especially its specific types: classes, enums, structs etc), you insulate your own code and have a single point to change when the library changes (for whatever reason).

  • My issue with that is that the distinction between "third party library", "core langauge library" and "own library" more or less is philosophical. And that in turn means that wrapping any third party libraries but not any internal is a weird choice, and that everything should be wrapped. – NiklasJ Mar 24 '16 at 12:41
  • @NiklasJ: Third party libraries may seem similar in that they are libraries, but there is a huge difference. You don't change core language libraries at will. In fact, in fact you only change them when upgrading your language version. And when a core language library changes you don't only have two options: port your own code or stay with the older version. No such constraints with third party libraries. You can use these regardless of their language/version as long as they support the platform (possibly .Net framework version) you are targeting. – Marjan Venema Mar 24 '16 at 15:10
  • @NiklasJ Own libraries should be treated as libraries. Certainly when it comes to version control etc. But there is no need to abstract it or hide it behind your own API as you are already in full control of that. – Marjan Venema Mar 24 '16 at 15:13
  • Still - more or less philosophical. I can ignore new versions of third party libraries and thus have the same situation as with core language libraries. I could use OS third party libraries and have the same situation as with my inhouse libraries. Further - for a large organization some parts may very well be more or less not under my control. The distinction really is very blurred and for me personally, I've switched to NOT wrapping third party libraries unless known with some certainty it will be needed. – NiklasJ Mar 25 '16 at 21:56
  • @NiklasJ You can't ignore third party library updates when they contain bugs that hamper you in your code. Yes the distinction may be blurred for all kinds of situations, but it doesn't take much to add that insulating layer and it will help you stay flexible, especially when other options are falling by the way side. – Marjan Venema Mar 26 '16 at 11:57
3

You could use a facade, something like

public interface ILocator { ... }

public interface IElementFinder {
  findElement(ILocator loc)
}

You would need to extract all relevant, general functionality from selenium to create the correct interfaces and then implement them as a thin layer.

This has a couple of downsides though - YAGNI as the top one, but also the fact that specific parts of your library might be dependent (in a good way) on the way specific parts of the library works.

A perhaps better way would be to extract all Selenium-specific code, use that in your own library, and hide that behind an interface.

Such as

interface IYourTestImplementation {...}
class SeleniumTestImplementation : IYourTestImplementation {...} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.