Page Object pattern and alternatives

2020-07-22 20:07发布

问题:

When you automate web UI testing you want to organize your tests so that they are maintainable and code duplication is minimized as possible. On of the way to go is Page Object pattern.

Did you try it in real world projects? Are there any alternatives? How do you model complex sites (few nested master pages, popups, large forms with crazy validations)? I'm interested in general patterns as well as in specific cases (Selenium/ASP.NET MVC/NUnit).

回答1:

You've asked quite a lot of questions, I'll try to answer a few of them.

I've used Page Object in a web app using Selenium and also in a desktop WinForms app (while that's not strictly Page Object, I've used it in the same way -- View Object, perhaps?). My verdict is that it works great and I'd definately recommend it.

Here's a short example of what a test might look like, the way we wrote it:

[Test]
public void AccountPageNameIsLoggedInUsersName()
{
    FirstPage() // Returns FirstPage
        .LoginAs("tobbe", "s3cr3t") // Returns LoggedInPage
        .ClickOnMyAccount() // Returns MyAccountPage
        .AssertThat(p => p.Name, Is.EqualTo("tobbe")); // p is of type MyAccountPage
}

Here, the Selenium magic is placed inside the FirstPage() method and the pages. This way you hide all the unnecessary implementation details from the test. I guess you can figure out how the methods are implemented.

A bonus from hiding the Selenium stuff inside the pages is that you could, without changing the test, convert it into e.g. a Model-View-Presenter test where the PageObject represents the view (that's similar to what I did in the WinForms app).

Regarding master pages, what we did is that we decorated the pages with an interface and created extension methods on those interfaces:

public class LoggedInPage : Page<LoggedInPage>, IMainMenuHolder { ... }

public static class MainMenuHolderExtensions
{
    public static MyAccountPage ClickOnMyAccount(this IMainMenuHoder me) { ... }
}


回答2:

We started using it as it makes sense. But we didn't want to write the common code our self so we looked around for some library that we could leverage. We found Geb. We already are using Spock so Geb + Spock are a very good match.



回答3:

I've written about complex page objects over at my blog. See http://burdettelamar.wordpress.com/2014/03/21/keep-your-page-objects-dry/

The idea is to share common page elements with inheritance (I'm writing in C#). In Ruby, you might use mix-ins; in Python, modules, etc.