-
Notifications
You must be signed in to change notification settings - Fork 4
Page Object
One of the most popular design patterns for test automation frameworks are the page object pattern. Page object pattern is used to:
- Wrap functionallity of the page or view to simple functions
- Hide complexity
- Remove duplication of code
Testura provides an additional nuget package to help you design and set up your test automation framework for the page object pattern.
https://www.nuget.org/packages/Testura.Android.PageObject
PM> Install-Package Testura.Android.PageObject
The package contains two classes:
- Applicaton - Your main class that will contain all views
- View - All your views will inherit from this class
Here we will show a quick example on how you can build your application and views class for a facebook application.
Let's start with our own facebook view class:
public abstract class FacebookView : View
{
protected FacebookView(IFacebookApplicationViews facebookApplicationViews, IAndroidDevice device) : base(device)
{
FacebookApplicationViews = facebookApplicationViews;
}
protected IFacebookApplicationViews FacebookApplicationViews { get; }
}
All our views will inherit from this base class and as you can see it take two arguments in the constructor:
- facebookApplicationViews - A reference to all views in our application (will show the implementation later)
- device - A reference to our device
We can then use this view class to create two example views(Note: all ids are made up and only used as examples):
public class LoginView : FacebookView
{
private readonly UiObject _id;
private readonly UiObject _usernameTextbox;
private readonly UiObject _passwordTexbox;
private readonly UiObject _loginButton;
private readonly UiObject _errorLabel;
public LoginView(IFacebookApplicationViews facebookApplicationViews, IAndroidDevice device) : base(facebookApplicationViews, device)
{
_id = device.Ui.CreateUiObject(With.ResourceId("somethingUniqueOnView"));
_usernameTextbox = device.Ui.CreateUiObject(With.ResourceId("usernameId"));
_passwordTexbox = device.Ui.CreateUiObject(With.ResourceId("passwordId"));
_loginButton = device.Ui.CreateUiObject(With.ResourceId("loginButtonId"));
_errorLabel = device.Ui.CreateUiObject(With.ResourceId("errorLabelId"));
}
public LoginView Exist()
{
if (!_id.IsVisible())
{
throw new ViewException("Can't find the login view.");
}
return this;
}
public MainView Login(string username, string password)
{
Exist();
_usernameTextbox.InputText(username);
_passwordTexbox.InputText(password);
_loginButton.Tap();
if (_errorLabel.IsVisible())
{
throw new LoginException($"Failed to login, error: {_errorLabel.Values().Text}");
}
return FacebookApplicationViews.MainView;
}
}
public class MainView : FacebookView
{
public MainView(IFacebookApplicationViews facebookApplicationViews, IAndroidDevice device) : base(facebookApplicationViews, device)
{
}
}
With all views done we can move over to the application classes. We first need an interface that contains all views in our application.
public interface IFacebookApplicationViews
{
MainView MainView { get; }
LoginView LoginView { get; }
}
Finally we can create the main application class where we set up the device and all views
public class FacebookApplication : Application, IFacebookApplicationViews
{
private IAndroidDevice _device;
/// <summary>
/// Set up our device and register and solve all dependencies
/// </summary>
public void SetUp()
{
_device = new AndroidDevice(new DeviceConfiguration { ShouldInstallDependencies = false });
Container.RegisterInstance<IAndroidDevice>(_device);
Container.RegisterInstance<IFacebookApplicationViews>(this);
RegisterViewDependencies();
SolveViewDependencies();
}
/// <summary>
/// Start the ui server and go to the main activity
/// </summary>
/// <returns></returns>
public LoginView Start()
{
_device.Ui.StartUiServer();
_device.Activity.Start("facebookPackage", "facebookActivity", forceStopActivity: true, clearTasks: false);
return LoginView;
}
public LoginView LoginView { get; protected set; }
public MainView MainView { get; protected set; }
}
The most important thing here is the SetUp method. When we call the SetUp method it will:
- Create and set up a new device
- Register the device to our unity container
- Register ourself as the IFacebookApplicationViews interface (so views can access other views)
- Go through all properties in our class that inherit from the View-class and register them in our unity container
- And finally solve all dependencies
If you haven't use dependency injection before I would recommend to read this: https://en.wikipedia.org/wiki/Dependency_injection
When everything done, let's create our first tests (in this example we're using NUnit)
[TestFixture]
class LoginTest
{
private FacebookApplication _facebookApplication;
[OneTimeSetUp]
public void SetUp()
{
_facebookApplication = new FacebookApplication();
_facebookApplication.SetUp();
}
[Test]
public void Login_WhenHavingCorrectLoginInformation_ShouldLogin()
{
_facebookApplication
.Start()
.Login("myUsername", "myPassword");
}
[Test]
public void Login_WhenHavingIncorrectLoginInformation_ShouldNotLogin()
{
Assert.Throws<LoginException>(() =>
_facebookApplication
.Start()
.Login("myUsername", "wrongPassword"));
}
}