-
Notifications
You must be signed in to change notification settings - Fork 23
POP Rules
There are four main rules that we follow to keep our test suites consistent and useful. We learned from trial and error and found that these were the most important concepts to be aware of in order to be successful.
There should be a one to one mapping between pages in the app and page representations in your test code.
If you navigate away from a page or if a modal view covers the page so that you can no longer interact with the page underneath, then it should be considered a new page and you should define a new page class in your test code.
The following diagram illustrates what this should look like. Your test method calls into various pages that communicate with the corresponding pages in your app via Xamarin.UITest. Notice that each page in the test suite maps to a single page in the app.
Page classes save queries for all the elements on the page as fields at the top of the file.
Don't define any queries inside methods. Define them all as fields at the top of the class and assign them in the constructor based on the platform. This makes it easy to reuse and change the queries as needed.
public class LogInPage : BasePage
{
readonly Func<AppQuery, AppQuery> EmailField;
readonly Func<AppQuery, AppQuery> PasswordField;
readonly Func<AppQuery, AppQuery> LogInButton;
protected override PlatformQuery Trait => new PlatformQuery
{
Android = x => x.Id("log-in-image"),
iOS = x => x.Id("sign-in-image")
};
public LogInPage()
{
// The same for both platforms
LogInButton = x => x.Id("log-in-button");
if (OnAndroid)
{
EmailField = x => x.Id("android-email-field");
PasswordField = x => x.Id("android-password-field");
}
if (OniOS)
{
EmailField = x=>x.Id("iOS-email-field");
PasswordField = x => x.Id("iOS-password-field");
}
}
}
Also, each page must define a Trait
property
The "trait" of a page is a query for some element unique to that page. The BasePage
uses a WaitForElement
to ensure that the trait appears (i.e. the page is fully loaded) before you can execute any methods on the page.
You should only interact with a page in the app through methods defined by the page representation.
If a method navigates away from the page (e.g. taps a button that goes to another page in the app), the method should return void
since you can no longer call more methods on that page.
Methods that do not navigate away from the page should return their own type (using return this;
) so that more methods can be called on the same object. This creates a fluent interface that is easy to work with.
new LogInPage()
.EnterCredentials("name", "password")
.ConfirmLogIn();
The benefit of the fluent interface is that you don't need to save the page to a variable so the code can be more concise.
There should be no calls to Xamarin.UITest in test methods, only in page methods.
Take another look at the above diagram and notice that only the the page representations ever interact with pages in the app via Xamarin.UITest. The test method never calls into UITest directly.
Don't use app.
in [Test]
methods. That is the pages' job. Tests should only instantiate new pages and make calls to those pages like so:
[Test]
public void LogInAndExploreTest()
{
new LogInPage()
.EnterCredentials("name", "password")
.ConfirmLogIn();
new HomePage()
.SelectFirstItem();
// ...
}