0

I have created my selenium tests however I would like to start cleaning them up for readability and reuse. What do you do with your variables?

I have thought about setting up some kind of dictionary of buttons that could be looked up but think that may cause more problems than solve.

        [Test]
        public static void TestAccrualRuleSet()
        {
            //Setup buttons and variables
            IWebDriver driver = new ChromeDriver();
            var hamburgerMenu = By.XPath("//*[@id='menu-toggle']/span/i");
            var settingsMenuButton = By.XPath("//*[@id='ulAdminNavBar']/li[4]/a");
            var timeAndLaborMgmtButton = By.XPath("//*[@id='ulAdminNavBar']/li[4]/ul/li[11]/a");
            var timeOffTrackingButton = By.XPath("//*[@id='ulAdminNavBar']/li[4]/ul/li[11]/ul/li[2]/a");
            var actionMenu = By.Id("ucAccrualRules_ddlAccrual");
            var ruleNameTextBox = By.Id("ucAccrualRules_ucAccrualRule_txtRuleName");
            var accrualRuleFrequencyDropDown = By.Id("ucAccrualRules_ucAccrualRule_cboAccrualType");
            var dropDownAccrualTypes = By.Id("ucAccrualRules_ucAccrualRule_hourTypes");
            var dropDownAccrualTypesCheckBox1 = By.Id("ucAccrualRules_ucAccrualRule_hourTypes_0");
            var dropDownAccrualTypesCheckBox2 = By.Id("ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_hourTypes_1");
            var dropDownAccrualTypesCheckBox3 = By.Id("ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_hourTypes_6");
            var maxCarryForwardTextBox = By.Id("ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_txtMaxRollover");
            var accrualWaitingTextBox = By.Id("ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_txtAccrualWaitingPeriod");
            var saveButton = By.XPath("//*[@id='ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_cmdUpdateName']");
            var savedSuccessfully = By.Id("ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_UCErrorRuleProperties_lblMessage");
            var propertiesButton = By.Id("ctl00_ContentPlaceHolder1_ucAccrualRules_ucAccrualRule_tpAccuralRulePropertiesnewForms");
            IJavaScriptExecutor js = (IJavaScriptExecutor)driver;

            //Begin test
            AppExtensions.LoginUsingChrome(driver);
            AppExtensions.SelectCompany(driver, "Ren's Test Account");
            System.Threading.Thread.Sleep(1500);
            WebDriverExtensions.Element_Click(driver, hamburgerMenu);
            System.Threading.Thread.Sleep(1500);

While this is not the whole test, it shows you an example of my huge list of variables I am using to store the buttons/links I need to perform my test. What is best practice regarding how and where these variables are stored for Selenium tests?

Soni K
  • 156
  • 2
  • 6
  • 19
J33NO
  • 839
  • 1
  • 8
  • 13
  • I recommend using page factory. – Shahboz Jun 11 '19 at 18:13
  • Create a file structure which holds the sequence of actions to run. I would break down each "test" into procedures and actions. (As I did with my "browsermator": https://www.browsermator.com ) The procedures correspond to a standard repeatable scenario or bug report. The entire group of procedures would be equivalent to a regression test. Why bother writing all this code defining variables when you can use your app to create/store/load them dynamically? – pcalkins Jun 11 '19 at 23:16

3 Answers3

1

It is recommended that you group variables in classes. You would have one class per page and move all variables for web elements of that page into respective class. This is called POM or Page Object Model. You can go further and add methods to those classes that cover multiple actions for that specific page or even navigation to other pages. Hint: Navigation methods would navigate and wait for the next page to be loaded and return an instance of that target page's POM class.

Cosmin Sontu
  • 1,034
  • 11
  • 16
  • So do you set every variable at the top of the class? Such as public static IWebDriver driver = new ChromeDriver(); – J33NO Jun 11 '19 at 16:49
  • Preferably the IWebDriver instance would not be part of your Page Object classes, but rather a singleton or passed as parameter in your Page Object classes via constructor. A good way to place IWebDriver is in the base class of your test class so you can initialize it and tear it down after each test. Your Page Object classes would contain your selectors as members and methods that interact with page elements via the driver instance. – Cosmin Sontu Jun 11 '19 at 22:07
  • Few years ago, I have written an automation framework in c# (that is a wrapper on top of WebDriver) which is opinionated on Page Objects. You can see an example test here : https://github.com/CosminSontu/SpecDrill/blob/master/SpecDrill.Tests/GoogleSearchTests.cs – Cosmin Sontu Jun 11 '19 at 22:10
1

Normally people go for 2 patterns:

  1. Object Repository - to store elements data in external source. Alternatively you can go for SpecFlow and keep element locators in Gherkin files.
  2. Page Object Model - abstraction layer for UI, the main idea is to split test logic from UI representation so if UI changes the test code still remains the same
Dmitri T
  • 159,985
  • 5
  • 83
  • 133
  • I actually used to keep the element locators in SpecFlow step definitions. This doesn't scale well for medium to large applications. The Page Object Model is definitely the way to go. – Greg Burghardt Jun 12 '19 at 11:48
0

One approach is you can create a properties file and maintain all your xpath etc in that. Then simply refer to the properties file in your class, for the varaible needs to be accessed using the xpath or locators. This way if any of xpath is changes, you have only one file to update that's the properties file. Example :

    Inside home.properties file you can have xpath as

searchBtn = //input[@elementid = 'abc']

this.properties = new Properties();
InputStream input = new FileInputStream("home.properties");
this.properties.load(input);
//Inside your class file you can access xpath as
    String searchBtn = By.xpath(properties.get("searchButton"))

I can't think of another approach.

Soni K
  • 156
  • 2
  • 6
  • 19
  • 1
    This would work for Java, but this question is about C#. – Greg Burghardt Jun 11 '19 at 17:40
  • 1
    I like this approach, I just tried it within a class and it works nicely but it would make adding new variables more cumbersome. Because every time you needed to add one, you would need to switch over to another file/class and add it then reference it. – J33NO Jun 11 '19 at 17:41
  • sometime, you can maintain an excel spreadsheet or text file and read those from excel spreadsheet or text file. It will be easy to maintain but you still have to write code/functions to read those files or just manipulate methods to suit your needs. – Soni K Jun 11 '19 at 17:54