Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / testing

5 Reasons You Should Use the Brand-New C# 7.0 in Your WebDriver Tests

4.88/5 (8 votes)
26 Feb 2017Ms-PL3 min read 13K  
Learn how to use the brand-new C# 7.0 to make your WebDriver tests even better. Utilise the power of local functions, digit separators and much more.

I believe that you need to always play with the latest technologies to be great in what you are doing. As I promised in my last article Enhanced Selenium WebDriver Tests with the New Improved C# 6.0, now I am going to share with you how you can utilize the power of the brand-new C# 7.0. I am not going to cover all of the features because I don't like some of them or I don't see how we can use them in the tests. You can find even more cool tips and tricks about automated testing in my WebDriver Series.

Quick Navigation

Digit Separator

Prior C# 7.0

There are lots of times where we use number literals in our code. Because of the many zeroes for me, it is hard to distinguish what is the value of the timeout.

C#
[TestInitialize]
public void SetupTest()
{
    driver = new FirefoxDriver();
    driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(30000);
}

Another example when we use digits in our tests is when we pass expected values.

C#
[TestMethod]
public void SearchTextInBing_First()
{
    var bingMainPage = new BingMainPage(driver);
    bingMainPage.Navigate();
    bingMainPage.Search("Automate The Planet");
    bingMainPage.AssertResultsCount(236000);
}

C# 7.0 Version

You can put digit separator _ wherever you want between digits, to improve readability. They have no effect on the value.

C#
[TestInitialize]
public void SetupTest()
{
    driver = new FirefoxDriver();
    driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30_000);
}
C#
[TestMethod]
public void SearchTextInBing_First()
{
    var bingMainPage = new BingMainPage(driver);
    bingMainPage.Navigate();
    bingMainPage.Search("Automate The Planet");
    bingMainPage.AssertResultsCount(236_000);
}

Local Functions

Prior C# 7.0

There are many times when we create private methods that are just called in a single method in our class so that we can improve the readability. However, when the class is too long, you need to jump back and forth between different methods to get the big picture. In the example, we pass the purchase order objects to the private method so that the expected values are formatted in the proper way.

C#
public partial class ShippingAddressPage
{
    public void AssertPurchaseOrders(List<PurchaseOrder> purchaseOrders)
    {
        for (int i = 0; i < purchaseOrders.Count; i++)
        {
            Assert.AreEqual(GetFormattedPurchaseOrder(purchaseOrders[i]), PurchaseOrderRows[i].Text);
        }
    }

    private string GetFormattedPurchaseOrder(PurchaseOrder purchaseOrder)
    {
        return $"Your product: {purchaseOrder.ProductName} costs {purchaseOrder.Price}";
    }
}

C# 7.0 Version

Now we can declare methods that can be used only in the current block scope (e.g. current method). The previous private method now is part of the Assert. I think this improvement makes the Assert much more readable.

C#
public partial class ShippingAddressPage
{
    public void AssertPurchaseOrders(List<PurchaseOrder> purchaseOrders)
    {
        string GetFormattedPurchaseOrder(PurchaseOrder purchaseOrder) => 
            $"Your product: {purchaseOrder.ProductName} costs {purchaseOrder.Price}";
        for (int i = 0; i < purchaseOrders.Count; i++)
        {
            Assert.AreEqual(GetFormattedPurchaseOrder(purchaseOrders[i]), PurchaseOrderRows[i].Text);
        }
    }
}

Extended Expression Bodied Constructor

Prior C# 7.0

C#
public partial class ShippingAddressPage
{
    private readonly IWebDriver driver;

    public ShippingAddressPage(IWebDriver browser)
    {
        this.driver = browser;
    }

    // some other actions
}

C# 7.0 Version

If the constructor of the page is so simple, we can convert it to just a single line instead of three!

C#
public partial class ShippingAddressPage
{
    private readonly IWebDriver driver;
    public ShippingAddressPage(IWebDriver driver) => this.driver = driver;

    // some other actions
}

Extended Expression Bodied Properties

Prior C# 7.0

Sometimes, it can make sense not to return the whole element instead to make the element's property of type string. This way, you can only assign and get values. This can improve the API usability (all other WebDriver's properties and methods are restricted). The drawback here is that you need eight lines of code for each getter and setter.

C#
public partial class ShippingAddressPage
{
    public string Country
    {
        get
        {
            return new SelectElement
            (driver.FindElement(By.Name("enterAddressCountryCode"))).SelectedOption.Text;
        }
        set
        {
            new SelectElement(driver.FindElement
             (By.Name("enterAddressCountryCode"))).SelectByText(value);
        }
    }

    public string FullName
    {
        get
        {
            return driver.FindElement(By.Id("enterAddressFullName")).Text;
        }
        set
        {
            driver.FindElement(By.Id("enterAddressFullName")).SendKeys(value);
        }
    }

    // other elements
}

C# 7.0 Version

Now, you can use extended bodied expressions for both the getters and the setters. We reduced the code from eight lines to just two.

C#
public partial class ShippingAddressPage
{
    public string Country
    {
        get => new SelectElement(driver.FindElement
        (By.Name("enterAddressCountryCode"))).SelectedOption.Text;
        set => new SelectElement(driver.FindElement
        (By.Name("enterAddressCountryCode"))).SelectByText(value);
    }

    public string FullName
    {
        get => driver.FindElement(By.Id("enterAddressFullName")).Text;
        set => driver.FindElement(By.Id("enterAddressFullName")).SendKeys(value);
    }
}

Throw Expressions

Prior C# 7.0

We need to guard our code (methods/constructors). I believe that test code is a production code so it should be treated like such. Here, if the driver is null, we throw an exception.

C#
public partial class ShippingAddressPage
{
    private readonly IWebDriver driver;

    public ShippingAddressPage(IWebDriver driver)
    {
        if (driver == null)
        {
            throw new ArgumentNullException(nameof(driver));
        }
        this.driver = driver;
    }
}

C# 7.0 Version

Now you can throw an exception inside the constructor's extended bodied expression. With the new syntax, we saved seven lines!

C#
public partial class ShippingAddressPage
{
    private readonly IWebDriver driver;
    public ShippingAddressPage(IWebDriver driver) => 
      this.driver = driver ?? throw new ArgumentNullException(nameof(driver));
}

So Far in the 'Pragmatic Automation with WebDriver' Series

References

The post 5 Reasons You Should Use the Brand-New C# 7.0 in Your WebDriver Tests appeared first on Automate The Planet.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)