UI objects are an invaluable resource when it comes to writing UI tests for enterprise applications. They identify and represent elements, sections or sometimes web pages or windows (depending on the context) as “objects” which can be used with an object oriented language and a browser automation tool such as Selenium to create your tests.
There are significant advantages of this approach. First, representing UI elements as objects which can be used within your test code allows you to re-use the UI objects in different tests. Also, by using UI objects, you can clearly segregate test logic from the UI logic as all the UI related complexities are encapsulated within the UI object.
One of the major disadvantages of using UI object approach is that the UI object creation/generation process is not governed by tests (See Figure 1). This surfaces some critical issues. First of all our UI object repositories can get really large and clogged with objects that are not required for our tests at all. This happens because UI objects are generated early before the tests are created, we don’t exactly know which part of the UI elements we require for the test. Furthermore, this disconnect approach restrict us to make the UI Objects more context aware, i.e. there might be an opportunity to refactor the UI object to handle some responsibilities other than encapsulating sub components and its location. For instance, it will be more logical to encapsulate the “login” functionality within the Login UI object rather than handling that logic within the tests. However, we can’t make an informed decision about this until we get down to writing actual tests. Also, the approach of creating UI objects first set a trend to write the test based on the generated object rather than basing them on the actual business requirement.
Figure 1 illustrate the usual approach of using a UI object repository
As a developer or a tester our objective is to test the functionality of our application through the UI, however, the above approach will force us to focus unnecessarily on object creation. The situation worsens when we consider the fact that the action of creating UI objects and the action of writing tests are independent of each other. UI object creation should be done as part of creating tests and it should be a natural flow rather than a step we must follow.
UI Object repositories are just a mere tool that we use to write tests. Hence, there is a clear dependency between the two, test objects will always be composed of UI objects and UI objects can’t exist without a test.
Figure 2 illustrates this dependency
The flow depicted in Figure 1 above doesn’t endorse the relationship shown in figure 2.
We propose a solution for the above presented issues and to ensure that relationship shown in figure 2 is always honored. The proposed approaches ensures the UI object creation process is governed by tests, it follows a flow defined in below in figure 3
As shown in Figure 3, this approach enforces you to write a failing test first. You are forced to use a UI object that doesn’t exist; hence, your test will fail. You will then define the minimum required object to pass the test. This is the most important aspect of this approach, rather than mapping your UI’s one to one into objects, you are creating a UI object that is only complete enough to pass the test you are writing at that moment.
Further explaining the “Minimum Required Object”, properties of being minimum and required should be maintained at all times. I.e. these objects should have 100% code coverage from the test suite. The approach shown in figure 3 ensures this will always be true. At the inception of the object creation, you will only represent UI components that are absolutely required to run the test you are writing at the given time, obviously you will revisit this object multiple times as your test or test suite grows.
While this approach will resolve many issues in creating objects prior to writing tests, the problem of context switching can still be a problem if you are using a 3rd party tool to generate objects for your tests, in that case you will be switching context very frequently since you should neither create the object nor the test at one go. However, this issue is heavily dependent on the mechanism you use to generate UI Objects. For instance, if you are not using a 3rd party tool and choose to create UI objects directly using the object oriented language you use to write tests, i.e. manually creating UI objects; there’s no issue of context switching since you are doing it within the same context. This approach has merit of removing the dependency on 3rd party object generators, remove the learning curve of a 3rd party object generator and provide the maximum control of your objects. One negativity in this approach is that you are responsible of organizing your objects; and how quickly you can do changes to UI objects will entirely depend on your ability to organize them in a meaningful manner. Figure 4 illustrates this approach.
Organizing your objects in a separate project and under well-structured packages will help you to avert the aforementioned issue.