WebDriver Intro: Build a Netflix Test Framework

WebDriver Intro: Build a Netflix Test Framework

Learn How To Structure Your Code to Make it Super Easy To Build Readable Test Cases. I Teach The Basics of Using Fluent Interfaces and How They Can Dramatically Improve the Readability of Your Tests.

Years ago I worked with a QA guy who was building out a test framework. He liked to write his code to be as efficient as possible. To him that meant squeezing in as much functionality into as few methods as he could.

When you read his tests you’d find very few methods, sometimes as few as one or two. Most of the methods were built in a way that the user had to pass in tons of parameters.

He thought that was just great.

The problem with his approach was he was pushing his efficiencies up to the very top where the tester would need to deal with them.

Instead of being straight-forward and easy to use, his additions to the framework forced everyone else to worry about how the framework actually worked.

His efforts to improve usability were actually making the framework harder to use.

Keeping It Simple Guarantees People Will Use It.

If you want to build a successful suite of automated tests, then people need to want to use it. To get people to do that, you need to make the framework dead simple to use.

If testers need to have to constantly figure out how the framework actually works, then they won’t use it.

In my perfect QA world, a test framework would be so easy to use that anyone who had to use it would be able to write tests that easily covered all the functionality of the product under test.

My favorite way to do this is to write code that has an easy-to-read, almost fluid style to it. A good way to do that is to use nested classes and nested methods, but with a bit of a twist.

A nested class (NinjaB) is one that’s contained inside another (NinjaA). NinjaB is then considered nested. This is standard stuff in software development.

But if you use a little creative license when naming your classes and methods, they start to resemble a natural sounding language when you chain them together.

You basically end up with something that sounds and reads like a sentence.

For example:

BookSearchPage.SearchForSubject("Dinosaurs").FilterByAuthor("Smith").SortResultsBy("Date").Go

As you type out your test, it starts to read like an actual sentence.

You can write different methods to do different things, like filtering by author, or filtering by category, and just drop them in to change up the tests.

This was the 10,000 foot view of how nesting your classes can improve the readability of your test framework.

Lets get into the nuts and bolts of how we’d use this to build actual test cases.

This test case will be specifically designed to login to a little website called Netflix.

netflix logo

Write What You Need First

It’s good practice to write out the test case first, and then build the test framework after to support it.

This helps to ensure you don’t start building more framework than you need.

NetflixLoginPage.LoginAs("you@youremail.com").WithPassword("supersecret").Login();

When you read that out, it sounds something like this:

On the Netflix Login Page, Login As “you@youremail.com” With Password “supersecret”, then click Login.

It sounds like steps you’d take to manually test this, right? It sounds natural and fluid because it closely mimics the steps a user would take to login to Netflix. This is key. We’re able to do this because we named the classes and methods so they sound natural.

Let’s take a look.

<public class NetflixLoginPage
{
    public static LoginSequence LoginAs(string userName)
    {
        return new LoginSequence(userName);
    }
}

public class LoginSequence
{
    private string email;
    private string password;

    public LoginSequence(string email)
    {
        this.email = email;
    }

    public LoginSequence WithPassword(string password)
    {
        this.password = password;
        return this;
    }

    public void Login()
    {
        var EmailInput = Driver.Instance.FindElement(By.Id("email"));
        EmailInput.SendKeys(email);

        var PasswordInput = Driver.Instance.FindElement(By.Id("password"));
        PasswordInput.SendKeys(password);

        var LargeSignInButton = Driver.Instance.FindElement(By.CssSelector(".btn.login-button.btn-submit.btn-small"));
        LargeSignInButton.Click();
    }
}

Ok so there’s definitely a lot more to unpack now.

In this case I’m using two classes, NetflixLoginPage and LoginSequence.

The NetflixLoginPage class contains a single method called “LoginAs”.

Its going to be the start of what I’ll call a LoginSequence – it represents all of the steps needed to login to Netflix.

When we call NetflixLoginPage.LoginAs(“you@youremail.com”) , the LoginAs method stores the username within an object of type LoginSequence, then returns the object. This is what kickstarts our login to Netflix.

Within the LoginSequence object are two more methods, “WithPassword” and “Login“.

When “LoginAs” returns, it passes control to the WithPassword()  method where it stores the password “supersecret”.

The last method to run is Login() . This is the method that performs the actual work. The first two methods (LoginAs and WithPassword) were just used to store variables.

The Magic is to Chain Your Methods With Readable Names

Remember how the point to this is to build a framework that’s easy-to-use and maintain?

When you type in NetflixLoginPage and then hit the period key, Visual Studio will show you a list of methods that are immediately available directly inside the class.

Structuring your framework like this, and naming the methods appropriately, limits how the tester can build out his or her tests to exactly what’s supported by the framework.

As they’re typing out their tests, they can see immediately the functionality that’s already been built into the framework.

This also has the useful effect of making it easy to chain together testable commands.

The Netflix LoginPage will have a few other things to do on it:

  • You can recover a forgotten password,

  • You can signup to create a new account.

These aren’t technically on the same page, so we can break these out into their own classes.

We can define two more page classes called LoginHelpPage and SignUpPage. Each will contain their own classes called RecoverPasswordSequence and SignupSequence.

The different test cases could look like this:

RecoverPasswordPage.RecoverPasswordUsingEmail("you@youremail.com").ClickEmailMe()
RecoverPasswordPage.RecoverPasswordUsingTextMessage("123-123-1234").andCountry("Canada").ClickTextMe()
RecoverPasswordPage.RecoverPasswordUsingVoiceCall("123-123-1234").andCountry("Canada").ClickCallMe()

and

SignUpPage.SignupWithName("Bobby", "McGee").andPassword("spiceychicken").Go()

 

Thank You!


I hope you enjoyed this tutorial.


If it has helped you in any way, please do me a favor and let me know in the comments section below. And don’t forget to grab a copy of the Visual Studio solution I used in this tutorial.



 

Leave a Reply