Behavior Object Model
Tags: testing, selenium
Published: 2020-03-07 01:03:42

This post is related to UI based testing, specifically with Selenium.

If you are working with Selenium and going through courses one of the important learning points is to design your tests around the "Page Object Model." I would like to take this opportunity to supply an alternative to this approach to specifying locator and behaviors. This is to say that there are use-cases in which the "Page Object Model" may not be the correct choice, but is not to say that it replaces that model.

Let me start by providing my understanding and description of what the Page Object Model is to help contrast with this alternative model.

# Page Object Model

This model states that your page component should have a class representing the component and its available behaviors.

The benefit here is that you have created a single place of ownership for your locators. It also allows for defining interactions allowing for the class be a single location to update behavior for all your tests.

You will notice that I state components instead of page. This is because some components could exist across pages and these components can still be used to build a true page representation.

# Behavior Object Model

## Background

This is not a replacement so it is a good idea to understand my situation a little bit. 

I test a single page application, it has some basic interface elements and new components are added/removed as needed. More importantly those base elements also become available or not based on these transition and even implementations (because we produce customization per client). 

If we build a page object determining what a "component" is becomes useless. Either we define our component with more than different tests need or we define the component too small and every test will need 5 or more components. It becomes difficult to know what is required to exist on the page for this test to be relevant. 

## Test Behaviors

Tests are written to verify behaviors. This behavior is defined as "specific interaction, produce expected results." 

This means we want tests which interact with the page to verify those actions create desired results. 

## Model

The desired locators needed by the test are defined by the test. Which opens up the question, isn't this defining the same locators across tests? 

This is prevented through a form of masking. Each locator is defined along side every other locator used by the tests. I will use the following defined locators and the login testing:

* Basic login functions 
* Basic with two factor auth
* Oauth login 
* Oauth with two factor auth

![Page Map](https://img.photobucket.com/albums/v128/he_the_great/ByObjectMasking.gif)

This can be used with the page object model. If you have been going through the [Test Automation Academy](https://testautomationu.applitools.com/test-automation-framework-csharp/chapter3.html), he utilized C# and calls it a Page Map. 

## Dependency Injection

The behavior object model relies on dependency injection for the locators. Remember I stated that we are writing our tests for behavior and the elements our locators point to influence the behavior of the application. 

If we want to test our login behavior, then the username element being a text field will have a different experience than our username being a drop down list. In the page object model you would supply the user name and password with the details ignored. 

```csharp 
public void Login(BasicLogin locator, string username, string password) {
   Driver.FindElement(locator.username).Type(username);
   Driver.FindElement(locator.password).Type(password);
   Driver.FindElement(locator.login).Click();
}
```

This allows for helping methods to be created which specify the needed locators.

```csharp 
public class BasicLogin {
    public SerializableBy username { get; set; } 
    public SerializableBy password { get; set; } 
    public SerializableBy login { get; set; } 
} 

public class AddressForm {
[°°°] 
} 

public class TestLocators : AddressForm, BasicLogin {
[°°°] 
} 

```

Our API can define the specific locators desired and the test locators can just inherent the locators it needs, except we are using C#, multiple inheritance does not exist and interfaces can not implement methods. I'm hoping [interface default methods](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods) might be used here. 


{% link https://dev.to/jessekphillips/serialize-selenium-by-in-c-51ik %}