【问题标题】:Unnecessary class instantiation repetition不必要的类实例化重复
【发布时间】:2020-07-20 20:49:47
【问题描述】:

目前正在使用 C# 和 SpecFlow 构建自动化框架。目前我的一个抱怨是我实例化一个类以访问方法或 Web 元素的次数。

下面是我在单独的类方法中实例化的类的一部分

public class UniversalSelectors : BasePage
{
    public  UniversalSelectors(IObjectContainer container): base(container)  { }

    //iFrame
    public IWebElement iFrame => Driver.FindElement(By.Id("content"));
    //Nav Bar Elements
    public void ClickAdministration()
    {
        Driver.FindElement(By.XPath("//a[@id='administration-menu-item']"));
    }
    public void ClickDevicesMenu()
    {
        Driver.FindElement(By.XPath("//*[@id='manage-devices-menu-item']"));
    }
    public void ClickRemoteMonitoring()
    {
        Driver.FindElement(By.Id("manage-monitoring-menu-item"));
    }
    public void ClickSystemUsers()
    {
        Driver.FindElement(By.XPath("//*[@id='manage-users-menu-header']"));
    }
    //Quick Search Elements
    public IWebElement Quick_Search => Driver.FindElement(By.XPath("//*[@class='pSearch pButton']"));
    public IWebElement Quick_Search_Box => Driver.FindElement(By.XPath("//*[@class='qsbox']"));
    public IWebElement Quick_Search_Button => Driver.FindElement(By.XPath("//*[@class='btn btn-sm btn-success flexigrid-search-button']"));
    public IWebElement Quick_Clear_Button => Driver.FindElement(By.XPath("//*[@class='btn btn-sm btn-success flexigrid-clear-button']"));

您可以在下面看到我是如何在不同类的每个方法中实例化的。但我想知道的是,这是必要的还是有更好的解决方法?

public void NavigateToRoles()
{
    var universalselectors = new UniversalSelectors(_container);

    universalselectors.ClickAdministration();
    Thread.Sleep(1000);
    universalselectors.ClickSystemUsers();
    Thread.Sleep(1000);
    Roles.Click();
    Thread.Sleep(2000);
}
public void CreateBlankRole()
{
    var universalselectors = new UniversalSelectors(_container);

    Driver.SwitchTo().DefaultContent();
    Driver.SwitchTo().Frame(universalselectors.iFrame);
    universalselectors.ClickNewRecord();
    Thread.Sleep(2000);
    universalselectors.ClickSaveRecord();
    Thread.Sleep(2000);
}

【问题讨论】:

  • 那么您想消除或减少初始化 UniversalSelectors 的次数吗?
  • NavigateToRolesCreateBlankRole 方法属于哪个类?这些类和方法与您的步骤定义和功能文件有什么关系?
  • 是的,所以想知道是否有办法只在每个类中初始化 UniversalSelectors 一次,而不是在每个方法中单独初始化
  • 这些方法位于称为角色的页面对象类中,它们链接到与功能文件相关的步骤定义。我还有一个基本年龄类,其中填充了可以被它绑定的任何类访问的方法。把初始化放在那里有用吗?

标签: c# selenium automation instantiation specflow


【解决方案1】:

您可以避免使用dependency injection 初始化相同类型的新对象(另请参阅constructor injection)。在 SpecFlow 的范围内,这涉及在 SpecFlow hook 中创建 UniversalSelectors 的新实例并将其注册到 SpecFlow 对象容器。接下来,任何需要页面模型的步骤定义类都应包含一个 UniversalSelectors 对象作为其构造函数参数之一,并将其​​与 Web 驱动程序对象一起传递给页面模型的构造函数。

向 SpecFlow 依赖注入框架(对象容器)注册 Web Driver 和 UniversalSelector 对象:

[Binding]
public class SpecFlowHooks
{
    private readonly IObjectContainer container;

    public SpecFlowHooks(IObjectContainer container)
    {
        this.container = container;
    }

    [BeforeScenario]
    public void BeforeScenario()
    {
        var driver = new ChromeDriver() | FirefoxDriver() // or whatever web driver you use

        // Configure the web driver

        var universalSelectors = new UniversalSelectors(driver);

        container.RegisterInstanceAs<IWebDriver>(driver);
        container.RegisterInstanceAs(universalSelectors);
    }
}

现在,将 UniversalSelectors 对象添加到页面模型的构造函数参数中:

public class RolesPageModel
{
    private readonly IWebDriver Driver;
    private readonly UniversalSelectors universalSelectors;

    // other properties

    public RolesPageModel(IWebDriver driver, UniversalSelectors universalSelectors)
    {
        Driver = driver;
        this.universalSelectors = universalSelectors;
    }

    public void NavigateToRoles()
    {
        universalselectors.ClickAdministration();
        Thread.Sleep(1000);
        universalselectors.ClickSystemUsers();
        Thread.Sleep(1000);
        Roles.Click();
        Thread.Sleep(2000);
    }

    public void CreateBlankRole()
    {
        Driver.SwitchTo().DefaultContent();
        Driver.SwitchTo().Frame(universalselectors.iFrame);
        universalselectors.ClickNewRecord();
        Thread.Sleep(2000);
        universalselectors.ClickSaveRecord();
        Thread.Sleep(2000);
    }
}

将事物结合在一起的粘合剂在于您的步骤定义,您还需要向这些构造函数声明 UniversalSelectors 参数:

[Binding]
public class RoleSteps
{
    private readonly RolesPageModel roles;

    public Roleteps(IWebDriver driver, UniversalSelectors universalSelectors)
    {
        roles = new RolesPageModel(driver, universalselectors);
    }

    [When(@"I create a blank role")]
    public void WhenICreateABlankRole()
    {
        roles.CreateBlankRole();
    }
}

附录

在我看来,真正的问题是 UniversalSelectors 类本身。 “选择器”(或 Selenium 用语中的“定位器”)可以在使用定位器的页面模型中轻松声明。事实上,这是首选方法。页面具有通用元素,例如导航菜单和搜索栏。这些常见的页面元素应该是它们自己的页面模型。组合而不是继承在这里更有用:

public class RolesPageModel
{
    private readonly IWebDriver Driver;
    private readonly NavigationBarPageModel navBar;
    private readonly SiteSearchBarPageModel searchBar;

    // other properties

    public RolesPageModel(IWebDriver driver)
    {
        this.driver = driver;
        navBar = new NavigationBarPageModel(driver);
        searchBar = new SiteSearchBarPageModel(driver);
    }

    public void NavigateToRoles()
    {
        navBar.GoToRoles();
    }

这简化了所有页面模型的依赖关系,并完全消除了对 UniversalSelectors 的需求。

【讨论】:

    猜你喜欢
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-13
    • 1970-01-01
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多