SOLID - Open/Closed principle - Part 2
Decorator design pattern is used to add functionality to an object dynamically without the need of modifying the structure of the object. Decorator pattern is used to attach functionality or behavior to an object dynamically or statically without the need to altering the object's structure.
Decorator classes
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.VisualStudio.TestTools.UITesting;
namespace TestFramework.UI.Web.Attributes
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class SearchByAttribute : Attribute
{
public SearchByAttribute(string name, string value)
{
Name = name;
Value = value;
ConditionOperator = PropertyExpressionOperator.Contains;
}
public SearchByAttribute()
{
ConditionOperator = PropertyExpressionOperator.Contains;
}
[Required(AllowEmptyStrings = false, ErrorMessage = "Name is a required property when using a search condition")]
public string Name { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Value is a required property when using a search condition")]
public string Value { get; set; }
public PropertyExpressionOperator ConditionOperator { get; set; }
}
}
Using the Decorator class in the client class.
using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestFramework.UI.Web.Attributes;
using TestFramework.UI.Web.Model;
namespace TestFramework.UI.Web.UITests.Pages
{
public class CustomPage : Page
{
[Control(Id = "PlaceHolder", IdConditionOperator = PropertyExpressionOperator.Contains, Class = "navigation-menu")]
public HtmlDiv NavigationMenu { get; set; }
[Parent("NavigationMenu")]
[SearchBy(Name = "Title", Value = "")]
[Control()]
public HtmlHyperlink MenuLink { get; set; }
[Parent("NavigationMenu")]
[SearchBy(Name = "Title", Value = "", ConditionOperator = PropertyExpressionOperator.Contains)]
[SearchBy(Name = "href", Value = "", ConditionOperator = PropertyExpressionOperator.Contains)]
[Control()]
public HtmlHyperlink MenuLink { get; set; }
internal CustomPage AssertLinkExists()
{
//Mouse.Hover(GremiaMenuLink);
Assert.IsTrue(MenuLink.Exists, "Failed to find navigational menu link on the page.");
return this;
}
internal CustomPage ClickOnKamerMenu()
{
//Mouse.Hover(GremiaMenuLink);
MenuLink.Click();
Playback.Wait(5000);
return this;
}
}
}
Accessing the control values using reflection.
System.Reflection.PropertyInfo property
var searchAttributes = property.GetCustomAttributes<SearchByAttribute>(false);
foreach (var searchAttribute in searchAttributes)
{
console.writeline((searchAttribute.Name + searchAttribute.Value + searchAttribute.ConditionOperator));
}