User Observable Locator Controversy
Generally test automators prefer to identify elements using the attribute: id, because it is unique on the page but also because it is less likely to change than text that is visible on the page. But I was intrigued by a brief post by Mark Borcherding in which he complains that "The ID isn't a user-observable attribute; however the text in the label is".
I can see that even though the text is more likely to change than the ID, it is immediately observable by the user and should be an obvious change. Where as if the developer changes the ID and doesn't communicate it, then it is more likely to result in a failed test; which takes time and effort to track down and repair.
The other desirable trait of using text is that sometimes you don't have a nice ID to use to identify an element. Often the element is some kind of child of an array. If you identify it by the exact relationship to the parent element, then if the layout gets changed, your test will fail. With a library like Capybara or SitePrism (Ruby gems) it is very simple to use the observable text without regard to the layout. Of course if the same text is used elsewhere on the page, then you need to indicate which instance you intend to target.
I am interested in the opinion of those that have far more experience with test automation than I have. Please comment with your experience and advice as to which is better. Thank you.
UPDATE: Newer browser test automation frameworks embrace using visual components. Read my post at https://www.dhirubhai.net/pulse/semantic-locators-eric-thomson/
?
ID is not a good idea as it makes it a unit test not a UI test as you are testing the internals of the page rather than how the page interacts with the user. Many test automation developers don't understand the difference and end up writing two types of tests in one - which is never a good idea. Most use ID cause it's "easier" - which just translates to "I'm lazy". Having "element + field + label name" means that it is very close to how a user would reference the field, e.g. when I click on the field next to the words "email" then i enter my email address. HTML spec says that a page cannot contain elements with the same ID (although due to lazy web devs over the years browsers allow it). If you are creating a component-based page with IDs you end up with "Component1", "Component2" or "ParentX_ParentY_Component", "ParentA_ParentB_Component" - neither way is more maintainable nor readable. A user would say "the email box down the bottom of the page not the one at the top" - so your find logic could indicate page location as well. Also if the page is to be translated into different languages using ID will always pass - however that may not be correct if the replaced text is the wrong way around (e.g. if "email" actually reads "name" in a different language - test passes but functionality is incorrect.) Not using ID makes it a little trickier to write the test - but ensures that the test is actually testing user "interaction" (what UI testing should really stand for), not browser rendering.
Author | Test Automation Coach | Solopreneur l Speaker | Trainer | Freelance Blogger | International Award-winning Software Engineer | I help teams succeed with Agile/DevOps by implementing real Continuous Testing
8 年I like using ID better, a simple reason is maintainability. From my experience, test maintenance (if projects are serious about test automation) requires much more effort than writing one (and pass it first time). Using ID does not necessarily equal to "less readable" (yes, less user - observable). The code "element :email, :field" comes from the perspective of A Page contains a list of elements. I see a Page is a collection of related operations (not attributes) user can perform one a web page. For example, in my page class, I will use def enter_email(email) driver.find_element(:id, "email_address").send_keys(email) end This way, I have flexibility of choosing most stable locator, send tab keys, add minor delay, scroll down to the make the element viewable and execute javascript in the function. As it is standard function, some testing IDEs may support auto-complete, refactoring, ..., etc At test script level, login_page.enter_email("[email protected]")