page object model: why not include assertions in page methods? page object model: why not include assertions in page methods? selenium selenium

page object model: why not include assertions in page methods?


As a guideline, assertions should be done in tests and not in page objects. Of course, there are times when this isn't a pragmatic approach, but those times are infrequent enough for the above guideline to be right. Here are the reasons why I dislike having assertions in page objects:

  1. It is quite frustrating to read a test that just calls verify methods where assertions are buried elsewhere in page objects. Where possible, it should be obvious what a test is asserting; this is best achieved when assertions are directly in a test. By hiding the assertions somewhere outside of a test, the intent of the test is not so clear.

  2. Assertions in browser tests can be expensive - they can really slow your tests down. When you have hundreds or thousands of tests, minutes/hours can be added to your test execution time; this is A Bad Thing. If you move the assertions to just the tests that care about those particular assertions you'll find that you'll have much quicker tests and you will still catch the relevant defects. The question included the following:

    Putting verification code in page methods multiplies the power of automation by allow you to get a lot of verification "for free"

    Well, "Freedom Isn't Free" :) What you're actually multiplying is your test execution time.

  3. Having assertions all over the place violates another good guideline; "One Assertion Per Test" ( http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html ). I don't stick religiously to it, but I try to follow the principle. Where possible, a test should be interested in one thing only.

  4. The value of tests is reduced because one bug will cause loads of tests to fail thus preventing them from testing what they should be testing.

    For example, let's imagine that when you login to your AUT, some text appears that says "logged in as USER". It's appropriate to have a single test validate this specifically, but why wouldn't you want to verify it every time login is called?

    If you have the assertion in the page object class and the expected text changes, all tests that log in will fail. If instead the assertion is in the test then only one test will fail - the one that specifically tests for the correct message - leaving all the other tests to continue running to find other bugs. You don't need 5,000 tests to tell you that the login message is wrong; 1 test will do ;)

  5. Having a class do more than one thing violates 'S' in SOLID, ie: 'Single Responsibility Principle' (SRP). A class should be responsible for one thing, and one thing only. In this instance a page-object class should be responsible for modelling a page (or section thereof) and nothing more. If it does any more than that (eg: including assertions) then you're violating SRP.


I too have struggled at times with this recommendation. I believe the reason behind this guideline is to keep your page objects reusable, and putting asserts inside your page objects could possibly limit their ability to be reused by a large number of unrelated tests. That said, I have put certain verification methods on my page objects like testing the caption for a header - in my experience, that is a better way to encapsulate test logic for elements of a page that don't change.

Another note - I have seen MVC applications that have domain models reused as page objects. When done correctly, this can significantly reduce redundant code in your testing library. With this pattern, the view models have no reference to a testing framework, so obviously, you could not put any asserts in them.


Your page object shouldn't perform an assertion because then the page object has to know about your test framework (unless you're using built-in language assertions). But your page needs to know it's state to locate elements and perform actions.

The key is in the statement "Of course, as with every guideline there are exceptions..."

Your page should throw exceptions, not perform assertions. That way your test can catch the assertion and bail or act accordingly. For instance.

page = ProfilePage.opentry   page.ChangePassword(old, new)catch notLoggedIn  page.Login(user, pass)assert page.contains "your password has been updated"

In this limited example you'd have to check again (and again) so it might not be the best way, but you get the idea. You could also just check state (twice)

if page.hasLoginDialog  page.Loginif page.hasLoginDialog //(again!)  assert.fail("can't login")

You could also just check that you have a profile page

try   page = site.OpenProfilePagecatch notOnProfilePage

or has the elements you need try profilepage.changePassword(old,new) catch elementNotFound

or without throwing an exception

page = site.OpenProfilePageif ! page instanceof ProfilePage

or with complex checking

assert page.looksLikeAProfilePage

It's not how you do it that matters. You want to keep logic in your tests to a minimum but you don't want your page objects to be tied to your test framework -- after all, you might use the same objects for scraping or data generation -- or with a different test framework that has it's own assertions.

If you feel a need you can push your assertions out of your test case into test helper methods.

page = site.GoToProfilePagevalidate.looksLikeProfilePage(page)

which a great opportuntity for a mixin if your language supports them, so you can have your clean page objects -- and mixin your sanity checks.