The PageObject design pattern plays the role of modeling areas of UI within test code where methods of PageObjects return other PageObjects. In reality, this concept is similar to the class we saw in the Using Classes as Test Modules where methods return Boolean. This design pattern replaces the Boolean with actual PageObjects which are classes with test code. I wrote about this pattern initially in the context of Selenium (see here) – this article is simply a port to vbs/QTP.
Consider the example below where the Exec method of LoginPage class returns InboxPage.
''Login PageObject Class LoginPage Public Function Exec(ByVal user, ByVal pass) 'Return InboxPage PageObject Set Exec = New InboxPage End Function End Class Dim Login Set Login = New LoginPage ''Inbox PageObject Class InboxPage Public Function GetUnreadMailCount 'code End Function End Class 'Login.Exec(arg, arg) returns the InboxPage PageObject Set InboxPageObject = Login.Exec("User", "Pass") 'The returned object (InboxPage) from the previous statement 'can be used to execute the method GetUnreadMailCount iUnreadMails = InboxPageObject.GetUnrealMailCount()
The example above is in its simplest nature. In reality, a single process can return multiple PageObjects. For example, a Login process can return 2 types of page objects: Inbox PageObject (pass) or the Login PageObject (fail).
From the figure above, the Inbox PageObject is returned when the supplied login credentials are valid. In case of invalid login credentials, the process fails and the user is asked to attempt logging into the application again. Because of this behavior, it becomes necessary to build logic for both successful and unsuccessful events.
'Launches the application Class LaunchApp Public Default Function Run() 'Return Nothing if the initialization fails Set Run = Nothing With Browser("title:=.*Mercury.*") If Not .Exist(0) Then SystemUtil.Run "iexplore.exe", "http://newtours.demoaut.com" End If If .WebEdit("name:=userName").Exist(10) Then 'Return the LoginPage PageObject if UserName field is found Set Run = New LoginPage End If End With End Function End Class 'Login process Class LoginPage Public Default Function Run(userName, password) With Browser("title:=.*Mercury.*") .WebEdit("name:=userName").Set userName .WebEdit("name:=password").Set password .Image("name:=login").Click() .Sync If InStr(.GetROProperty("title"), "Find a Flight") > 0 Then 'If Welcome page appears = User has logged in 'Return FindAFlightPage Object Set Run = New FindAFlightPage Else 'If the Welcome page failed to appear = Login failed 'Stay at the Login Page Set Run = Me End If End With End Function End Class 'Contains methods for the Inbox page Class FindAFlightPage 'returns SelectAFlightPage Public Function GotoSelectFlightsPage() 'code End Function ' other methods End Class
The code below shows how the PageObjects above can be used to build tests in QuickTest. Like the 3 classes shown above, the test-code class will also be stored in the function library because by default, classes are private and Actions cannot access classes directly.
The PageObjects created above can be executed the following way:
Set LoginPageObject = (New LaunchApp).Run() Set InboxPageObject = LoginPageObject.Run("test", "test")
In summary, public methods of the classes in this pattern represent the functionality the page offers. A single class may comprise of multiple public methods which may return 1 or more PageObjects. If it also a good practice to keep the internals of the page as private, to avoid exposing them. Also, a PageObject need not represent an entire page. In practice, it can only represent a section or functionality that may be required to execute several times.