Tuesday, June 14, 2016

Knockout Placeholder Select Binding

So, for whatever reason, the select tag does not support the placeholder attribute. If it did, I'm assuming that's what the Knockout binding for optionsCaption would end up setting. I tried a few approaches to get a placeholder effect from the select box and have a decent working example. Of course, as is true with most coding questions, I started with a quick search of stack overflow. I took the example that worked the best for my scenario and turned it into a knockout binding.
At first, I thought I should extend the existing select binding, however, I soon realized there is no select binding; it just uses value, options, optionsText, ... to accomplish its task. So, I looked into adjusting the optionsCaption binding, and saw that it is just part of the options binding and I followed suit.

ko.bindingHandlers.placeHolderSelect = {
    after: ['options', 'value', 'optionsCaption'],
    init: function (elem, value, allBindings, viewModel, bindingContext) {
        var options = ko.utils.unwrapObservable(value());

        if (allBindings['has']('optionsCaption')) {
            var caption = $(elem).find('option[value=""]');

            if (options === 'required') {
                caption.prop('hidden', 'hidden');
                caption.prop('disabled', 'disabled');
            }

            var emptyClass = 'empty';
            $(elem).change(function() {
                if (!$(elem).val()) {
                    $(elem).addClass(emptyClass);
                } else {
                    $(elem).removeClass(emptyClass);
                }
            });
            $(elem).change();
        }
    }
}

To use this binding, simply add placeHolderSelect and set the value to either 'required' if the selection should not allow the caption to be re-selected or any other value if the caption should allow re-selection.

    <!-- Cannot re-select caption -->
    <select data-bind="options: myOptions, optionsCaption: 'Caption Text', placeHolderSelect: 'required'"></select>

    <!-- Can re-select caption -->
    <select data-bind="options: myOptions, optionsCaption: 'Caption Text', placeHolderSelect: false"></select>
Enjoy!

Monday, June 6, 2016

Decomposing Page Objects

This month has been heavily dedicated to defining a more robust approach to the page object pattern, which I have been calling Page Modeling. Page Modeling is not going away, however, in a recent 'twitter war' with Marcel de Vries, I was forced to really think about what the classic Page Objects pattern brings to the table that Page Modeling is 'missing' and to be able to highlight where Page Modeling fits into the picture.

This post is dedicated to decomposing the page object pattern into three distinct layers of abstraction. I believe that Page Objects have too many responsibilities and this leads to confusion / ambiguity on how to build the Page Object as well as having a need for multiple changes to the Page Object when only simple changes are made to the UI. Of course I will explain further about what this exactly means.

To start, I would like to identify three distinct aspect of the Page Object pattern which I feel should be decoupled.
  1. Page Modeling
    Finding UI elements on screen and exposing the behaviors and observations of those UI elements
  2. Orchestration
    Given the UI capabilities, what are the interesting things we can do
  3. Scenarios
    Given an orchestration, implements scenarios based on real user use of the application
I realized that page modeling alone does not provide all of the utility of page objects, but the additional utility can easily be added. Now, I will cover each aspect and how they can be assembled to implement the page object pattern in a far more robust and maintainable manner. The additional utility, however, doesn't really have a standard abstraction and would be custom to your application. This is because the higher level abstractions depend on the business concerns around how to use the application and are not representing the UI.

Page Modeling

I have covered Page Modeling in depth in previous blogs as well as CodedUI Examples website so I'll just summarize it here. Martin Fowler indicates that
The basic rule of thumb for a page object is that it should allow a software client to do anything and see anything that a human can. It should also provide an interface that's easy to program to and hides the underlying widgetry in the window.
At some point, you actually do need to interrogate that widgetry to test UI state and that the controls are behaving properly (formatting phone numbers, providing money with $, etc). This point is what makes the traditional page object pattern unmanageable as I will try to highlight below. Page Modeling hides the implementation of the widgetry so that the client doesn't care if they are using a TextBox, TextArea, MyCustomTextControl, etc... Page Modeling exposes the observations and behaviors of a UI element. So what are observations and behaviors you ask?

Behaviors

Behaviors are what the user can do with the UI. For instance, setting the value of a TextBox or Clicking a button. The result of a behavior is typically a Page Model representing the next most-likely thing with which the user will interact. This allows for a fluent syntax where the result of an action returns the next thing to work with.

Page Modeling


interface ILoginPage : IPageModel
{
    // instead, expose the components that allow a login to happen
    IReadWriteValuePageModel<string, ILoginPage> Username {get;}
    IReadWriteValuePageModel<string, ILoginPage> Password {get;}
    ISelectionablePageModel<ILoginPage> RememberMe {get;}
    IClickablePageModel<IAccountSettings> Login {get;}
}

interface IAccountSettings : IPageModel
{
    IReadWriteValuePageModel<string, ILoginPage> FirstName {get;}
    IClickablePageModel<IAccountSettings> Save {get;}
}

public void LoginAndSetFirstName()
{
    ILoginPage loginPage = new LoginPage(browserWindow);// get a reference to the login page

    Assert.IsFalse(loginPage.Login.IsActionable()); // IsActionable <=> enabled and visible
    
    Assert.IsTrue(loginPage.UserName.SetText("MyUserName") // set the username which returns reference to the login page
                           .Password.SetText("MyPassword") // set the password which returns reference to the login page
                           .Login.IsActionable());

    IAccountSettings accountSettings = loginPage.Login.Click(); // click login which returns a reference to account settings page

    // from here, I could do more, but the above logic would probably be refactored out into a Scenario
    // IAccountSettings accountSettings = new LoginScenario(loginPage).LoginStandardUser();

    Assert.IsFalse(loginPage.IsRendered());
    Assert.IsTrue(accountSettings.IsRendered());

    string myName = "MyName";
    accountSettings.FirstName.SetText(myName) // set first name returns reference to account settings page
                   .Save().Click() // click save which returns a reference to account settings page
                   .FirstName.Value; // get the current value in the first name field after the page refreshes from the POST request

    Assert.IsTrue(myName.Equals(myName));
}

This fluent syntax is highly expressive of what the user is doing. In Page Objects, you would have a ton of methods like Is{control}{state}(). In Page Modeling, you have one property for each UI element {control} with methods like Is{state}(). Consider the difference below.

Page Objects


class LoginPage : Page
{
    AccountSettings Login(string username, string password);
    bool IsLoginButtonActionable();
}

class AccountSettings : Page
{
    // I can create one method for each property
    // AccountSettings UpdateFirstNameAndSave(string firstName); // oh boy... do not go this route!

    // or use optional parameters for what I want to set
    // which means every time fields are added or removed, this method has to change
    // and the logic inside is kinda crappy if(!String.IsNullOrWhitespace(firstName)) {/*set first name*/} ...
    AccountSettings SetUserInfoAndSave(string firstName = null, string lastName = null, DateTime? birthDate = null);

    // what about reading?  either need a class/struct to hold all the values
    AccountInfo GetUserInfo();

    // or one for each; again, no clear answer
    string GetFirstName();
}

public void LoginAndSetFirstName()
{
    var loginPage = new LoginPage(browserWindow);
    Assert.IsFalse(loginPage.IsLoginButtonActionable());

    // If I login, I can't assert anything about the button, so let me go update my class...
    loginPage.Login("myUser", "myPass");
}

// updating LoginPage
class LoginPage : Page
{
    AccountSettings Login(string username, string password);
    bool IsLoginButtonActionable();
    LoginPage SetUsernameAndPassword(string username, string password);
}

// updating Test
public void LoginAndSetFirstName()
{
    var loginPage = new LoginPage(browserWindow);
    Assert.IsFalse(loginPage.IsLoginButtonActionable());

    loginPage.SetUsernameAndPassword("myUser", "myPass");
    Assert.IsTrue(loginPage.IsLoginButtonActionable());

    // now, I want to login, but I only need click the login button
    // there is no way to do that, I have to either do a .Login call
    // to (again) set the username and password, or update my class!
}

// updating LoginPage
class LoginPage : Page
{
    AccountSettings Login(string username, string password); // no enforcement that this calls SetUsernameAndPassword which may have special logic for setting
    bool IsLoginButtonActionable();
    LoginPage SetUsernameAndPassword(string username, string password);
    AccountSettings ClickLogin(); // assuming only use this method in conjunction with SetUsernameAndPassword method
}

// updating Test
public void LoginAndSetFirstName()
{
    var loginPage = new LoginPage(browserWindow);
    Assert.IsFalse(loginPage.IsLoginButtonActionable());

    loginPage.SetUsernameAndPassword("myUser", "myPass");
    Assert.IsTrue(loginPage.IsLoginButtonActionable());

    var name = "myName";
    IAccountSettings accountSettings = loginPage.ClickLogin();
    accountSettings.SetUserInfoAndSave(firstName: myName);
    Assert.IsTrue(name.Equals(GetFirstName()));
    Assert.IsTrue(name.Equals(GetUserInfo().FirstName));
}

Not only are there a bunch of methods, but there are overlapping concerns and an ambiguous development strategy. There are two ways to login now. Login() and SetUsernameAndPassword() followed by ClickLogin(). Along the way, multiple methods were added just to test something about the UI. In Page Modeling, there is no ambiguity. Simply, there is a property per UI element that exposes what it can do and what about it can be observed.

Observations

Observations are what the user can observe about your UI. For instance, what is the current value of the text box, is the element visible, does it exist on the screen, is it enabled, ... Observations should not have side affects and should not require an action from the user whenever possible. Sometimes this is unavoidable and the observation becomes more similar to a behavior. However, as long as the side affect or user action doesn't require manipulation of state outside of the UI elements control, it is typically safe. An example of this would be that the value of a TextBox is obscured until you click the eyeball in the textbox. An observation that read the text by first clicking the eyeball if needed, and then resetting the state to obscured would be OK. There should be a way to tell if the state of the box is obscured or plain for rigorous testing.

Orchestration

Orchestrations is simply defining meaningful strings of actions against a page model and exposing only the dependencies of that string of actions to the client to call. Using the above case of a login page, an orchestration method may be the Login(string username, string password) method. The orchestration simply takes a reference to whatever page model it orchestrates and uses the exposed observations and behaviors to create a meaningful set of actions.

interface ILoginActions
{
   IAccountSettings Login(string username, string password);
}

public class LoginActions : ILoginActions
{
    public readonly ILoginPage loginPage;
    public LoginActions(ILoginPage loginPage)
    {
       this.loginPage = loginPage;
    }

    public IAccountSettings Login(string username, string password)
    {
       // the orchestrator does not typically need to make assertions,
       // and can assume that there are tests for Login actions
       return
       this.loginPage
           .Username.SetValue(username)
           .Password.SetValue(password)
           .Login.Click();
    }
}

// using the orchestration in a test
public void LoginAndSetFirstName()
{
    var loginPage = new LoginPage(browserWindow);

    // do not care how to actually login
    IAccountSettings accountSettings = new LoginActions(loginPage).Login("myUsername", "myPassword");

    // perform the interesting work of setting name and asserting
    accountSettings.FirstName.SetValue("myName").Save.Click();
    Assert.IsTrue("myName".Equals(accountSettings.FirstName.Value));
}

// could even create extension methods
public static class LoginActionExtensions
{
    public static IAccountSettings Login(this ILoginPage loginPage, string username, string password)
    {
        return new LoginActions(loginPage).Login(username, password);
    }
}

// using the extension in the test seems more natural
public void LoginAndSetFirstName()
{
    // no need to new up some orchestrator class, just get the page and use the extension
    IAccountSettings accountSettings = new LoginPage(browserWindow).Login("username", "password");

    // perform the interesting work of setting name and asserting
    accountSettings.FirstName.SetValue("myName").Save.Click();
    Assert.IsTrue("myName".Equals(accountSettings.FirstName.Value));
}

Using the orchestration classes, tests which are dependent on some previous page model (eg, must first login to get to desired page), can use the orchestration class to not worry about how to perform the given action while knowing that the details are thoroughly tested elsewhere. Commonly used orchestrations would typically become scenarios, which are described next.

Scenarios

Scenarios are even higher level abstractions than orchestrations and they perform a real world user use of the application. Consider you have three types of users: Basic, Premium, and Administrator. Each type would have different login credentials and those credentials could change or even the way login is performed could change, but the Scenario shields tests from these issues. Methods of a Scenario should typically not require any dependencies exposed to the client.

interface ILoginScenarios
{
    IAccountSettings LoginBasicUser();
    IAccountSettings LoginPremiumUser();
    IAdminDashboard LoginAdminUser(); // notice, we're going somewhere else after login; this would be annoying to handle in a test
}

public class LoginScenarios : ILoginScenarios
{
    public readonly ILoginActions loginActions;
    protected readonly BrowserWindow window;

    public LoginScenarios(ILoginPage loginPage, BrowserWindow window) : this(new LoginActions(loginPage), window) { }

    public LoginScenarios(ILoginActions loginActions, BrowserWindow window)
    {
        this.loginActions = loginActions;
        this.window = window;
    }

    public IAccountSettings LoginBasicUser()
    {
       return this.loginActions.Login("basicUsername", "basicPassword");
    }

    public IAccountSettings LoginPremiumUser()
    {
       return this.loginActions.Login("premiumUsername", "premiumPassword");
    }

    public IAdminDashboard LoginAdminUser()
    {
       // don't return as it's not the right model
       this.loginActions.Login("adminUsername", "adminPassword");
       return new AdminDashboard(this.window);
    }
}

// and possibly extensions here as well
public static class LoginScenarioExtensions
{
     public static IAccountSettings LoginBasicUser(this ILoginPage loginPage)
     {
        return new LoginScenarios(loginPage).LoginBasicUser();
     }

     public static IAdminDashboard LoginAdminUser(this ILoginPage loginPage)
     {
        return new LoginScenarios(loginPage).LoginAdminUser();
     }
}



Of course, the downside with extension method approach is that the extension method class cannot implement the interface it reflects, but you could do something more elegant. Let's combine the power of all three layers into a single Facade.

public LoginFacade : ILoginPage, ILoginActions, ILoginScenarios
{
    public readonly ILoginScenarios LoginScenarios;
    public ILoginActions LoginActions => this.LoginScenarios.LoginActions;
    public ILoginPage LoginPage => this.LoginActions.LoginPage;
    protected readonly BrowserWindow window;

    public LoginFacade(ILoginPage loginPage, BrowserWindow window) : this(new LoginActions(loginPage), window) { }
    public LoginFacade(ILoginActions loginActions, BrowserWindow window) : this(new LoginScenarios(loginActions), window) { }
    public LoginFacade(ILoginScenarios loginScenarios, BrowserWindow window)
    {
       this.LoginScenarios = loginScenarios;
       this.window = window;
    }

    // delegate all actions
    IReadWriteValuePageModel<string, ILoginPage> Username => this.LoginPage.Username;
    IReadWriteValuePageModel<string, ILoginPage> Password => this.LoginPage.Password;

    public IAccountSettings Login(string username, string password)
    {
        return this.LoginActions.Login(username, password);
    }

    public IAdminDashboard LoginAdminUser()
    {
        return this.LoginScenarios.LoginAdminUser();
    }
}



And we have come full circle. There is now a master object that can do all three layers which the client can manipulate. Each layer is exposed so that tests can test the granular widgetry if needed or simply use an orchestration or scenario to navigate past the already tested workflows of the application.

Hopefully I've convinced you that decoupling the Page Object pattern is worth the effort and reduces ambiguity while increasing consistency of the testing strategy.

Sunday, June 5, 2016

Change Image Source on Hover using Knockout JS

I found this js fiddle for how to do it using jQuery so I converted it to use a Knockout binding.  Surprisingly, the first page of google didn't have any KO binding to do it.

ko.bindingHandlers.hoverImage = {
  init: function(element, valueAccessor) {
    var options = ko.utils.unwrapObservable(valueAccessor());
    $(element).bind('mouseover', function(event) {
      var $this = $(this);
      if (!$this.data('original-image')) {
          $this.data('original-image', $this.attr('src'));
      }
      $this.attr('src', options);
    })
    .bind('mouseout', function(event) {
       var $this = $(this);
       $this.attr('src', $this.data('original-image'));
    });
  }
};
To use it,
<img src="initialImageSrc.jpg" data-bind="hoverImage: 'hoverImageSrc.jpg'>

Saturday, June 4, 2016

Proper Page Modeling - In depth

In a previous article, I tried to explain why the page object pattern that I have seen described is simply lacking from what it could be.

Let's start with the good things about page objects.

1.  They are an abstraction of what the page should do
2.  They provide an implementation agnostic approach to testing (don't care if wpf, html, etc)
3.  They allow for more easily readable, and therefore more maintainable, code
4.  They provide a easy to understand navigation pattern where the result of actions are the next thing to work with

Ok, great.  How is this accomplished.  Let's look at an example in depth and compare what I've seen as 'traditional' page objects and compare to my approach to page modeling.

Let's take two pages into account.  Login page and Account Settings page.




When you login successfully, you'll go to the account settings page.

In code, your traditional page objects may look something like this.

class LoginPage : Page
{
    /// Logs in using the credentials supplied
    AccountSettings Login(string username, string password, bool rememberMe);
    RegisterPage ClickRegisterLink();
    ForgotPasswordPage ClickForgotPassword();
    AccountSettings LoginWithTwitter(string twittername, string twitterpass);
    AccountSettings LoginWithFacebook(string facebookname, string facebookpass);
}

I think this much we can agree upon.  Now, where it starts to fall apart for me.  Here is a quote from uncle bob martin.

There are differences of opinion on whether page objects should include assertions themselves, or just provide data for test scripts to do the assertions. Advocates of including assertions in page objects say that this helps avoid duplication of assertions in test scripts, makes it easier to provide better error messages, and supports a more TellDontAsk style API. Advocates of assertion-free page objects say that including assertions mixes the responsibilities of providing access to page data with assertion logic, and leads to a bloated page object.
I favor having no assertions in page objects. I think you can avoid duplication by providing assertion libraries for common assertions - which can also make it easier to provide good diagnostics. 

I agree with no assertions in page objects.  He makes an aside that I also agree with:
One form of assertions is fine even for people like me who generally favor a no-assertion style. These assertions are those that check the invariants of a page or the application at this point, rather than specific things that a test is probing. 
So, I know that there are more things about this page like, is the login button enabled when no username or password is present.  Here are two ways I can extend this class:

class LoginPage : Page
{
    bool IsValid();
}

In this case, how do I know what is not valid so I can fix it?  Also, what does the logic look like for this method?

public bool IsValid()
{
    if(String.IsNullOrEmpty(username.Text) || String.IsNullOrEmpty(password.Text))
    {
        if(loginButton.Enabled)
        {return false;}
    }
    else
    {
        if(!loginButton.Enabled){ return false; }
    }

    // .. maybe more tests for other requirements?
    // what about this?
    // these are requirements for the page that these elements are visible
    if(!IsRegisterLinkVisible()) { return false; }
    if (!IsForgotPasswordLinkVisible()) { return false; }

    // and that they work?
    var registerHref = GetRegisterHref();
     using(var client = new HttpClient())
     {
         var result = await client.GetAsync(registerHref);
          if(!result.IsSuccessful) { return false; }
     }
    return true;
}

Or, I could just throw an exception so I can include detail about what is wrong:

class LoginPage : Page
{
    void ThrowIfNotValid();
}

but this is not good either.  I can't just ask the page if it's valid with out a try block.

So, I can expose all of the things I'm expecting?

class LoginPage : Page
{
    bool IsLoginButtonProperlyEnabledOrDisabled();
}

and then maybe a master IsValid that calls these and possibly throws an exception.

Now, say that the button is not supposed to be disabled, but it is supposed to be 'inactive', but still clickable to trigger form validation.

Ok, so I have to either update this method to

class LoginPage : Page
{
    bool IsLoginButtonPropertlyInactiveOrActive();
}

which is crazy.  Or, I can not rename the method and change the logic so that it doesn't really match.

Another approach to this would be just add methods for each thing you want to test.  Great,

class LoginPage : Page
{
    bool IsLoginButtonEnabled();
    LoginPage SetUsernameAndPassword(string user, string pass); // don't login, just set
}

but when requirement changes to inactive,

class LoginPage : Page
{
    bool IsLoginButtonActive();
}

So, requirements change again.  The password is only visible when a username with 6 or more characters is present.  Great, more methods.

class LoginPage : Page
{
    bool IsPasswordVisible();
    LoginPage SetUsername(string user);
}

To me, this is clearly a violation of open / close principal.  Especially since this is highly predictable.  UI elements have a natural set of consistent things you may want to do with them.  Testing UI elements for visibility, click-ability, enabled-ness, ... are extremely natural concerns and should be consistently available for all UI elements.

We'll look at crafting tests after the comparison with my approach to page modeling.

In my approach to page modeling, I strive for consistency of expression of the UI elements that create the control.  In my approach, the model looks like this:

// because of this inheritance, the login page is also testable for isvisible, exists, ...
interface ILoginPage : IPageModel
{
    // this type of method doesn't even belong here.  it belongs at some other level of abstraction
    // what a 'Login' action means is not any concern of this control
    //AccountSettings Login(string username, string password, bool rememberMe);

    // instead, expose the components that allow a login to happen
    IReadWriteValuePageModel<string, ILoginPage> Username {get;}
    IReadWriteValuePageModel<string, ILoginPage> Password {get;}
    ISelectionablePageModel<ILoginPage> RememberMe {get;}
    IClickablePageModel<IAccountSettings> Login {get;}

    // expose an object that supports click, and all native ui tests (is visible, enabled, ...)
    IClickablePageModel<IRegisterPage> Register {get;}
    IClickablePageModel<IForgotPasswordPage> ForgotPassword {get;}
    IClickablePageModel<ITwitterLoginPage> Twitter {get;set;}
    IClickablePageModel<IFacebookLoginPage> Facebook {get;set;}
}

Another interesting this happens here.  What happens if the facebook login button is on multiple pages.  The LoginWithFacebook(string facebookname, string facebookpass) logic has to be duplicated to all the pages that use it or some helper class is created to share logic.  Again, this belongs at a different level of abstraction for the testing.

To enable these scenarios, you could do something like:

class LoginPageUserActions
{
    protected ILoginPage LoginPage{get;}

    public LoginPageUserActions(ILoginPage loginPage)
    {
         this.LoginPage = loginPage;
    }

    public AccountSettings Login(string username, string password, bool rememberMe)
    {
         // even here, just assume that login works, no need for assertions
         // there should be tests to verify that login works
        return  this.LoginPage
                         .Username.SetText(username)
                        .Password.SetText(password)
                        .RememberMe.SetSelected(rememberMe)
                        .Login.Click();
    }
}

Now, lets compare how you write the tests for the above business requirements and implement the changes in both approaches.

Business Requirements:

1.  Main Login Control
-> Username, Password, and Remember Me all present and enabled
-> Login button visible, but disabled until username and password are set

2.  External Login Control
-> Facebook and Twitter links are present and enabled always

3.  Register Link
-> Present and enabled always

4.  Forgot password
-> Present and enabled always

5.  Upon successful login, the user lands on account settings page.

So the start of the test class would look like this:

public class LoginPageTests()
{
         protected BrowserWindow window;

         [TestInitialize]
         public void GivenLoginPage()
         {
              this.window = BrowserWindow.Launch("loginpageurl");
         }
}

I like to follow the Given, When, Then type of syntax where the Given is my test initialize as the arrange, the When and Then are part of the TestMethod as the act and assert.

To add the first business requirement for the main login control, we run into the first issue that I mentioned.  I could have an IsValid method that captures all this logic, or maybe an IsMainLoginControlValid method that only tests that part of the control.  Seems wrong for the model to do the testing; I would have thought the test class decides what IsValid means*. (* full disclosure, I violate this run on very rare occasion)

So maybe the test looks like:

public void ThenUsernamePasswordAndRememberMeVisibleAndEnabled()
{
    Assert.IsTrue(new LoginPage(this.window).IsValid());
}

Granted, it's short and sweet, it doesn't really tell me much.  And the next test would look the same:

public void ThenTheLoginButtonIsNotEnabled()
{
    Assert.IsTrue(new LoginPage(this.window).IsValid());
}

And finally some actual work:

public void WhenUsernameAndPasswordEntered_ThenLoginButtonIsEnabled()
{
    var loginPage = new LoginPage(this.window);
    Assert.IsTrue(loginPage.IsValid());
    loginPage.SetUsernameAndPassword("user", "pass");
    Assert.IsTrue(loginPage.IsValid()); 
}

Aside from the method name, I really have no idea what this would be testing for :)

Ok, so ditch the is valid approach and expose the methods of interest:

public void ThenUsernamePasswordAndRememberMeVisibleAndEnabled()
{
    var loginPage = new LoginPage(this.window);

    // add all these methods to the class first ~_~
    Assert.IsTrue(loginPage.IsUsernameVisible() && 
    loginPage.IsUsernameEnabled() &&
    loginPage.IsPasswordVisible() &&
    loginPage.IsPasswordEnabled());

    // maybe more simply, add these instead and hope you don't need to test them separately
    Assert.IsTrue(loginPage.IsUsernameVisibleAndEnabled() && loginPage.IsPasswordVisibleAndEnabled()); // still not great :/
}

public void ThenTheLoginButtonIsNotEnabled()
{
    Assert.IsFalse(loginPage.IsLoginButtonEnabled());
}

public void WhenUsernameAndPasswordEntered_ThenLoginButtonIsEnabled()
{
    loginPage.SetUsernameAndPassword("user", "pass");
   Assert.IsTrue(loginPage.IsLoginButtonEnabled());
}

To implement the next requirements, I would do the same thing = add tons of methods for testing the UI state, which are business requirements.  I'll skip 2, 3, and 4 for this reason.  You can imagine what that looks like.

The last requirement would involve the next page's model.  Presently, there is no way to test if the page is actually the page displayed to the user.  So maybe that should be in the isvalid method.  Or maybe it should be an IsPageVisible() method on the page object.

public void WhenValidCredentials_ThenAccountSettingsIsShown()
{
    var loginPage = new LoginPage(this.window);
    var accountPage = loginPage.Login("user", "pass");
    
    Assert.IsTrue(accountPage.IsPageVisible());
    Assert.IsFalse(loginPage.IsPageShown()); // there is no enforcement on consistency and someone named it differently...
}

Ok, so now the requirement changes.  

1.  Login button is not supposed to be disabled, it is supposed to be inactive and validation error is shown, if any, when clicked.
2.  Password is only visible if username with 6 or more characters is present.

In the case of IsValid, we'd go into the method and change the logic to reflect this, shuffle some test names around and add one test method:

// method name change
public void ThenUsernameAndRememberMeVisibleAndEnabledPasswordHidden()
{
    // body doesn't change as it doesn't really express much 
    Assert.IsTrue(new LoginPage(this.window).IsValid());
}

// method name change
public void ThenTheLoginButtonIsInactive()
{
    Assert.IsTrue(new LoginPage(this.window).IsValid());
}

public void WhenUsernameWithSixOrMoreCharacters_ThenPasswordIsShown()
{
     var loginPage = new LoginPage(this.window);
    Assert.IsTrue(loginPage.IsValid());
    loginPage.SetUsername("username");
    
     // still not an overly expressive test :/
    Assert.IsTrue(loginPage.IsValid()); 
}

In the case of exposing tons of methods for everything, you would change the IsEnabled methods to IsActive for the login button.  Not much different from the previous.

Using page models, lets do the same exercise.  Firstly, because of this approach, there is no ambiguity as to what methods to add to your UI.  Simply, you expose whatever UI elements are present and that is enough for the test to drive (or some middle, orchestration abstraction).

public void ThenUsernamePasswordAndRememberMeVisibleAndEnabled()
{
    var loginPage = new LoginPage(this.window);
     // more expressive about what is valid means for a given set of inputs (in this case, no inputs)
    Assert.IsTrue(loginPage.Username.IsActionable() && loginPage.Password.IsActionable() && loginPage.RememberMe.IsActionable());
}

public void ThenLoginButtonIsDisabled()
{
    Assert.IsTrue(new LoginPage(this.window).Login.IsNotEnabled())
}

public void WhenUsernameAndPasswordEntered_ThenLoginButtonIsEnabled()
{
    Assert.IsTrue(loginPage.Username.SetText("user")
                                        .Password.SetText("pass")
                                        .Login.IsEnabled())
}

public void WhenValidCredentials_ThenAccountSettingsIsShown()
{
    var loginPage = new LoginPage(this.window);
    // this method chain to login can be shared easily (see below)
    var accountPage = loginPage.UserName.SetText("user").Password.SetText("pass").Login.Click();
    
    Assert.IsTrue(accountPage.IsVisible());
    Assert.IsFalse(loginPage.IsVisible()); // enforcement on consistency
}

Notice, when writing these tests, I did not need to add anything to my model.  Also, there is room for a shared set of actions that are higher level that setting values and clicking things.  

public void WhenValidCredentials_ThenAccountSettingsIsShown()
{
    var loginPage = new LoginPage(this.window);
    var loginActions = new LoginPageActions(loginPage);
    var accountPage = loginActions.Login("username", "pass");
    
    Assert.IsTrue(accountPage.IsVisible());
    Assert.IsFalse(loginPage.IsVisible()); // enforcement on consistency
}

The underlying point I'm trying to make here is that you may want to very rigorously test the login page details in the login page tests, and then assume that login works in the shared code which does not need to be rigorous in assertions about page state.  This is probably my biggest gripe with page object pattern that I've seen explained.  It is not the page object's concern to know all these things.  It only stores values that may or may not be read and exposes hooks to click on things or other user actions.

So, to make the same requirement changes, nothing changes in the model.  Only the test for that requirement changes.

public void ThenUsernameAndRememberMeVisibleAndEnabledPasswordHidden()
{
     var loginPage = new LoginPage(this.window);
     // more expressive about what is valid means for a given set of inputs (in this case, no inputs)
    Assert.IsTrue(loginPage.Username.IsActionable() && loginPage.Password.IsNotRendered() && loginPage.RememberMe.IsActionable());
}

// method name change
public void ThenTheLoginButtonIsInactive()
{
    Assert.IsTrue(new LoginPage(this.window).Login.IsNotActive());
}

public void WhenUsernameWithSixOrMoreCharacters_ThenPasswordIsShown()
{
     var loginPage = new LoginPage(this.window);
     loginPage.Username.SetText("abc");
     Assert.IsTrue(loginPage.Password.IsNotRendered());
     loingPage.Username.SetText("userna");
     Assert.IsTrue(loginPage.Password.IsRendered());
}

Another point that falls out of this example is that in the traditional page objects approach, I had a Login(string username, string password, bool rememberMe) method for setting all three inputs and clicking login.  I had to add another method to only set username and password so I can test the login button visibility.  Then I had to add one to set only user name to test password visibility when requirement changed.

In this case, nothing had to be changed.  You can expect to want to test input boxes for visibility and to set and read text from them.

Now, we add in the requirement for the validation messages to be shown when login is clicked, but username or password not set.

In the traditional approach, we have to add a method for clicking the button (since we're not doing a login, but trying anyway; maybe the Login method allows empty string as input, or maybe it throws; so implementation details are bleeding out if I assume something about it).  Or a method to explicitly clear username or password and click ClickLoginWithoutUsernamePassword();

class LoginPage : Page
{
    // notice this return type is ambiguous.  If i click after SetUsernameAndPassword,
   // I would actually go to AccountSettingsPage, but I'm adding to satisfy test requirement
   // of click to fail
    LoginPage ClickLoginButton();
    AccountSettings ClickLoginButton2();

    LoginPage ClickLoginWithoutUsernamePassword(); // not ambiguous

    bool IsValidationMessageShown(); // maybe IsCorrectValidationMessageShown()?
     string GetValidationMessageText();
    // or worse
    bool IsExpectedValidationMessage(string message);
}

Notice, I have to add two methods for validation message:  Is it shown (not consistent naming) and what is the value of the text shown.  If I want to know more about the message, more methods!

Using page modeling, you get the login button click for free and just need to add a property for the validation message.

public ILoginPage : IPageModel
{
    IValuedPageModel<string, ILoginPage> ValidationMessage {get;}
}

and the tests for both:

// Using is valid is still not interesting
public void WhenNoUsernameAndLoginClicked_ThenValidationMessageShown()
{
    Assert.IsTrue(loginPage.IsValid());
    loginPage.Setusername("User");
    var page = loginPage.ClickLoginButton();

    Assert.IsTrue(loginPage.IsValid());
}

public void WhenNoUsernameAndLoginClicked_ThenValidationMessageShown()
{
      Assert.IsFalse(loginPage.IsValdationMessageShown());
      loginPage.SetUsername("username").ClickLoginButton();
      Assert.IsTrue(loginPage.IsValidationMessageShown());
       Assert.IsTrue(loginPage.GetValidationMessage().Equals(expectedMessage));
}

Again, very inconsistent methods and requirement to constantly add stuff to the page model.  With page modeling:

public void WhenNoUsernameAndLoginClicked_ThenValidationMessageShown()
{
      Assert.IsFalse(loginPage.ValidationMessage.IsRendered());
      loginPage.SetUsername("username").Login.Click();
      Assert.IsTrue(loginPage.ValidationMessage.IsRendered());
       Assert.IsTrue(loginPage.ValidationMessage.Text.Equals(expectedMessage));
}

Edit: Added examples for changing login method to require a pin

So, I was challenged that this approach is not maintainable considering the example of login changing to require a pin instead of a password.

I will show how page modeling is less affected by this change than page objects in this case.

Regardless, this is a large change.  In the case of page objects, I would update my login page as:

class LoginPage : Page
{
    // AccountSettings Login(string username, string password, bool rememberMe);
    AccountSettings Login(string username, int pin, bool rememberMe);

// all the IsPinVisible, IsPinEnabled methods have to replace the password ones
// and any orchestration method that uses password
    // bool IsPasswordVisible();
   bool IsPinVisible();

    // bool IsPasswordEnabled();
    bool IsPinEnabled();

   // there is nothing like this in page modeling to update since it belongs in a test
   // SetUsernameAndPin(string username, int pin);
}

This change requires EVERY test that logs in to change.  There is no avoiding this as the password type changed from string to int so at a minimum you'll have to make that change.

This is also true for the page modeling abstraction, but in a different way.  The orchestration layer is affected, and the tests for the login page it self are affected.

class LoginPageUserActions
{
    protected ILoginPage LoginPage{get;}

    public LoginPageUserActions(ILoginPage loginPage)
    {
         this.LoginPage = loginPage;
    }

    public AccountSettings Login(string username, int pin, bool rememberMe)
    {
         // even here, just assume that login works, no need for assertions
         // there should be tests to verify that login works
        return  this.LoginPage
                         .Username.SetText(username)
                        .Pin.SetValue(pin)
                        .RememberMe.SetSelected(rememberMe)
                        .Login.Click();
    }

    // there is no need for an orchestration method like SetUsernameAndPassword
    // it doesn't help anything and is added to page object purely to provide functionality for testing
}

This is exactly the same change that was required by page object.  However, the model for the page changes only by updating it's properties (do not need to change methods around at all since they have the same abstraction over the input).  This reflects much more accurately the real change.  The page added a pin and removed a password.

interface ILoginPage : IPageModel
{
     // password changes to pin
    // IValuable<string, ILoginPage> Password {get;}
    IReadWriteValuePageModel<int, ILoginPage> Pin{get;}
}

The only places that use the Pin directly are the tests for the login page itself.  Everything else uses the LoginPageUserActions orchestration wrapper.

To show what this would look like, lets continue on to the AccountSettings tests.

public class AccountSettingsTests
{
    BrowserWindow window;
    IAccountSettings accountSettings;

    [TestInitialize]
    public void GivenAccountSettingsPage()
    {
          this.window = BrowserWindow.Launch("loginpageurl");

          // before change to use pin
          //new LoginPageUserActions(new LoginPage(this.window)).Login("user", "password");

          // after the change to use pin
          this.accountSettings = new LoginPageUserActions(new LoginPage(this.window)).Login("user", 1234);
    }

    public void WhenChangeFirstNameAndSave_ThenFirstNameIsUpdated()
     {
            this.accountSettings.FirstName.SetText("New Value").Save.Click();
            this.window.Refresh();
            Assert.IsTrue(this.accountSettings.FirstName.Value.Equals("New Value"));
     }
}

Even if I have 1,000 tests in account settings, the only change was in Initialize().  Further, that change is required for page objects as well.

Now, the changes required to page objects are actually more because of the change required for all the methods.  Page Models had exactly one change and that was to remove old property and add new one.  Page objects has to replace all old methods with new ones.

In the page modeling approach, you have extensive tests for a given page and other pages use an orchestration class.  To me, this is far more maintainable than updating tons of methods.  Also, the Pin property is exactly the same as the Password property except that its .SetValue() method takes an int instead of a string.  Testing for visibility, enabled, etc... are all exactly the same and would not change in tests (aside from property name).  You could probably just do a refactor -> rename, change the type, and update the methods that use it to put an int when setting the text.  All other usage would be identical.


Friday, June 3, 2016

Proper Page Modeling (aka Page Objects)

It is making me crazy to see how many people are talking about Page Objects in what seems to be the least robust way possible.  I will try to keep it civil, but here are several examples of what I consider a terrible way to model your UI for testing:

http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern
http://fluentbytes.com/maintainable-test-automation-for-winforms-using-codedui/ (this one makes me particularly sad as it's Marcel and he's kinda the name for testing in this space ~_~)
https://www.youtube.com/watch?list=PL6tu16kXT9PoUbSYNcLrMG8ox6UBbbsCv&v=UUxSUsUVg-U

In all of these cases, the page objects have methods like .SetUserName("MyUserName"), .ClickLoginLink(), .LoginUser(string username, string password).

How terribly inconsistent and un-maintainable.  What if the user name input is not shown by default and there is a button that shows the user name box.  I'll have to add methods for .IsUserNameBoxVisible(), .ClickButtonToShowUserNameBox().  Wowzer.  As a tester who did not write the page object, I have no consistent expectation of what the page object can do or what the controls on the page can do or what I can assert about them.

Instead, the page object, which I'll now refer to as a Page Model, should expose the UserName input as a property which has methods for .IsVisible(), .Click(), .IsEnabled(), .SetText(string text).  Now, instead of .SetUserName("MyUserName"), it would be .UserName.SetText("MyUserName").  At a glance you may say, so what?  However, having the .UserName property gives me (for free) all of the common actions I may take.  For instance,

interface ILoginPage : IPageModel
{
    IReadWriteValuePageModel<string, ILoginPage> UserName {get;}
    IValuablePageModel<string, ILoginPage> Password {get;}
    IClickablePageModel<ILoginPage> ShowLogin {get;}
    IClickablePageModel<IAccountPage> Login{get;}
}

// page starts with username hidden
Assert.IsTrue(UserName.IsHidden());

// click show login button
ShowLogin.Click();

// assert that the user name is now visible
Assert.IsTrue(UserName.IsVisible());

// assert that the login button is disabled (no username / password entered)
Assert.IsTrue(Login.IsNotActionable());

// enter user name
UserName.SetText("MyUserName");

// assert login button is still disabled (no password)
Assert.IsTrue(Login.IsNotActionable());

// enter a password
Password.SetText("MyPassword");

// the login button should be enabled
Assert.IsTrue(Login.IsActionable());

Login.Click();

compared to

interface ILoginPage
{
    ILoginPage SetUserName(string userName);
    bool IsUserNameVisible();
    ILoginPage SetPassword(string password);
    ILoginPage ClickShowUsernameButton();
    bool IsLoginButtonEnabled();
    IAccountPage ClickLoginButton();
}

If I want to check if the password is visible, then I have to add it as a method.  If I want to check that the show username button disappears after clicking, I have to add a method.  This violates the Open / Close principal and in general is annoying.

It is the responsibility of the tests themselves to create these higher level concepts like

public void LoginUser(string username, string password)
{
    if(ShowLogin.IsVisible())
    {
         ShowLogin.Click();
    }

    UserName.SetText(username).Password.SetText(password).Login.Click();
}

Then, this can be reused in a test:

[TestMethod]
public void GivenLogin_WhenSaveFirstNameInProfile_ThenNameIsLoadedBack()
{
    var accountPage = LoginUser("someUser", "somePass");
    Assert.IsTrue(accountPage.IsVisible());

    string myName = "Myname";
    account.FirstName.SetText(myName).Save.Click();
    Logoff();

    accountPage = LoginUser("someUser", "somePass");
    Assert.IsTrue(myName.Equals(accountPage.FirstName.Value));
}