3

For a while I wrote test for our web application using the Page Object framework. But test after test, I notice, I always wrote the same kind of assert.

MyPage page = navigateToMyPage();
page.setField1("foo");
page.setField2("faa");
page = page.save();
assertThat(page.getField1(), is("foo));
assertThat(page.getField2(), is("aaa));

So I'm thinking about a PageObjectValidator.

MyPage page = navigateToMyPage();
page.setField1("foo");
page.setField2("faa");
page = page.save();
page.validate(); // or Validator.validate(page)

The idea is to centralize all the assert for a page, to not repeat them in each test (DRY) and to not forget one assert. Behind the scene, the setField1(String) function will put its parameter within a simple POJO, and the validate will iterate over all the properties of the POJO to do the assertion (to take an easy example).

What do you think about this idea? I'm not able to find any such example over web, If anyone have already implemented such a framework, provide your inputs here.

5 Answers 5

2

Martin Fowler discussed whether assertions should be included in page objects:

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. 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.

Page objects are commonly used for testing, but should not make assertions themselves. Their responsibility is to provide access to the state of the underlying page. It's up to test clients to carry out the assertion logic.

Following that if you have same assertions to be reused across multiple pages I would go for libraries

public class PageValidator extends TypeSafeMatcher<AnyPage> {

  public boolean matchesSafely(AnyPage page) {
    return page.getField1().equals("foo") && page.getField2().equals("aaa");
  }

  public static PageValidator isValid() { return new PageValidator(); }

}

that you can reuse easily:

assertThat(myPage, isValid());

Otherwise, if each page has different invariants I would define an interface

public interface PageValidator {
  boolean isValid();
}

that all page object classes must implement in their specific way.

0

If some asserts are always true, you can put them in the pageobject. But I found that most of my asserts depend on the situation, and test has more knowledge what is true - so for me makes more sense to make most asserts in test.

If you repeat some asserts often and from multiple tests, you can place them into a page method, but still call it from a test, when appropriate.

3
  • 1
    PageObject should only contains business action. Assert should be done somewhere else. As you said, common test should be put in a utility class.
    – tetienne
    Commented Oct 8, 2015 at 12:53
  • In Python, my page object classes are pretty compact, so I do not see the need to create utility classes. My programming is object-oriented, not object-obsessed, very pragmatic. I know that Java people feel differently. :-) Commented Oct 8, 2015 at 16:17
  • And I got a downvote without explanation, likely from some object-obsessed Java junkie... :-) Commented Apr 13, 2016 at 13:11
0

First of all you are thinking in right direction , so as to attained modularity. I have implemented this in my project (some sort of this) . You can try like this:

public bool validate(object pageCalled)
    {
        try
        {
            assertThat(pageCalled.getField1(), is("foo"));
            assertThat(pageCalled.getField2(), is("aaa"));
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("FAIL : " + ex.Message);
            return false;
        }
    }

this way if all asserts are passed it will return true and if anything turns out to be failure, exception will be catched and false will be returned.

Please reply if it works.

5
  • Your exemple will work indeed. But where your "foo" and "faa" come from? Necessarily you have to get them from somewhere. I think what I have in mind it's quite painful. For each page, I will have to create the PageObject, the associated model, and the wrapper. The 3 classes will implement the same interface. The test code will have to call the wrapper which will call the PO and the POJO.
    – tetienne
    Commented Oct 8, 2015 at 12:51
  • we can read it from CSV File. What I have done is, I have created a csv file with following headers: Page_Name, Value_1, Value_2, Value_3.... Then I have read those CSV and saved all rows data(except header row ) in dictionary object like Dictionary_Object(Key,List<String>). Key for each row will be its page name and based on that key, we will get the values in list type object and used that accordingly. Commented Oct 8, 2015 at 13:38
  • I really like your idea is really quite easier. Your file is used to run the test AND do the assertion. So you only have your page object class and your test read the file to know what to set. Do your CSV file used also to know which action to do or the actions are hardcoded in the test? What happened if the same page is used several time in your test? (create and update for instance)
    – tetienne
    Commented Oct 8, 2015 at 13:57
  • Actions are not hardcoded in the test. For each action, separate method is there like . CheckIsElementPresentOnPage(), CheckIsTextVisibleOnPage(). etc... Whatever action needs to be performed , its method can be called. Commented Oct 9, 2015 at 4:42
  • @tetienne , any update on this? Commented Oct 10, 2015 at 4:43
0

Page objects really should only be a control layer to the web page. Providing access to the individual operations a page can perform. If you want to group actions together, whether they are repeatable workflows, or groups of asserts, you could create page helper classes. Allow this helper class to accept your page object instance and then it can perform a series of repeatable actions with it.

This keeps the implementations of each action and the implementation of workflows that group actions together separated and each more manageable.

0

I tend to put very common assertions into either a POM or whatever class(es) I am extending to create the POM. Using BDD frameworks this makes it easier to write more dynamic statements while ensuring that no steps rely on another step.

For the following verification step:

Then the customer should be returned to Step3

I pull in the class associated with Step3 and then dynamically build it and run a method that is in the base class of my POM which does a pass/fail:

public By VerificationElementBy
def verifyStep() {
    assert this.driver.findElement(VerificationElementBy) != null
}

And my StepDef that executes the method:

@Then("^the customer should be returned to (.*)\$")
public void theCustomerShouldBeReturnedToStep(String stepNumber)  {
    StaticVars.Steps step = StaticVars.Steps.valueOf(stepNumber);
    Constructor<?> ctor = step.stepClass.getConstructor(WebDriver.class);
    ((StepPages) ctor.newInstance(driver)).verifyStep();
}

What is happening is a String is passed into the StepDef that is the classname for the POM. It then instantiates the class using reflection and then calls the verifyStep method to ensure that I am on the correct page.

This allows me to store a VerificationElement into the base class. Since my verification steps do not typically have an understanding of the rest of the test, I can use this assertion to ensure that the VerificationElement for the desired class is present and know which step my test is at during verification.

I find having base methods that return booleans to typically be the most effective, though when you always want a 'fail if x' having the assertion in the POM is fine.

Code Reduction, re-usability and fluidness of tests can sometimes require that the assertion be built into the POM.

2
  • Sorry, but I don't really understood your example. How can you add dynamically an assert on your page object?
    – tetienne
    Commented Apr 13, 2016 at 10:45
  • I added some more code to show how it is doing it. By extending a class, dynamically instantiating the new class and then calling a method in the extended class, it is able to return telling me whether the class is correct or not. I have to do it this way since my verification steps does not have the scope to any other test steps. This can be done for any assertions that would be usable on all of your test steps and are great when you're verification steps do not have scope to your test steps (IE, in Cucumber4JVM).
    – Paul Muir
    Commented Apr 13, 2016 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.