Wednesday, April 16, 2014

Short and to the point - BrightTalks meetup

I gave a presentation for the BrightTalks meetup about how I envision writing selenium tests. Read more about it here (http://www.meetup.com/Bright-Talks/events/174660312/)

Saturday, March 29, 2014

Are Spock and others dead?

I've been looking for a good alternative to writing unit tests, maybe in a more BDD-like form, or just to get some fresh perspective on how one could do unit tests. I think it's because me getting old and the middle-life crisis hitting on me :) And so I examined a few of the usual suspects in the Java space...

Spock

Some time ago I was extremely inspired by Spock. It was The Way to do unit tests. The introduction of a table-like construct to do multiple data-driven tests, labels for given/when/then template - that was awesome! I was hoping Peter Niederwieser would keep working on it forever but since he joined Gradelware his talent seems to be occupied elsewhere and Spock seems to be discontinued.

Fest Assert

I remember the time when Szczepan showed us fest-assert framework in action. Szczepan was well known for his passion for fluentization of all possible interfaces - which I strongly admire - but this, this was the real deal, the perfect combination of why and how to do things. I fell in love with this library, even started to create a .NET port of it and I'm still a fan. But it's been discontinued too. Luckily it's been picked up by Joel Costigliola and is being developed further as AssertJ. I sure hope this will keep being maintained!

TestNG

Now that's a fresh start I'm going to try to pursue. New annotations, a bit dangerous in what it tries to accomplish with the dependency on tests (I always hated that) but I'll try to give it a shot. And it's still maintained which is makes it stand out among other frameworks.

Geb

Now that's a good example of something one should never had created - a DSL to tackle a DSL. Wrr... I thought it couldn't get any worse but then I found...

Fluentlenium

Well,... It seems like someone tried to kind of repeat the success of fest-assert and got it wrong. I tried it and it is just... wrong.

Conclusion

From what I've been able to figure out in a few hours it seems like only TestNG is the only actively developed alternative to JUnit and one of the very few frameworks in the testing space that actually makes any advancements. But hey - I might very well be wrong. If you can share a link to something revolutionary in the testing space drop me an email ad padcom (at) gmail (dot) com or leave a comment below.

Happy testing!


Thursday, February 20, 2014

Selenium and reusable scenarios

In my last post I've shown you how to structure your code describing the application under test so that it allows for easier construction of more readable integration tests. Today I'll try to complement that with the concept of reusable blocks of tests - scenarios.

Let me give you an example of a scenario that everyone can relate to: logging in to an application. Let's consider what does it actually take to perform this task:

  • navigation to the login page
  • entering proper credentials
  • clicking the "Login" button

Doing that in every test every time will soon make the tests unmaintainable. For example changing username and/or password or adding language to the login page when you do this 200 times is just going to be a huge pain in the neck.

Scenario concept to the rescue.

Let's imagine our base Page object contains this kind of method:

public <I extends Page, O extends Page> O run(Scenario<I, O> scenario) {
    return scenario.run(this);
}

Having defined this let's see the Scenario interface:

public interface Scenario<I extends Page, O extends Page> {
    O run(I entry);
}

The I generic parameter is the type of the page that you'd like to start the scenario on. The O generic parameter is the resulting page the scenario ends on.

Now the definition of the login scenario from the last post would look something like this (extended with language selector):

public class LoginScenario implements Scenario<LoginPage, HomePage> {
    private final String username;
    private final String password;
    private String language = "english";

    public LoginScenario(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public HomePage run(LoginPage entry) {
        return entry
            .assertHasProperUsernameLabel()
            .assertHasProperPasswordLabel()
            .enterCredentials(username, password)

            .selectLanguage(language)
            .clickLogin()
            .assertPageTitleIs("Welcome to this cool application!");
    }


    public LoginScenario language(String language) {
        this.language = language;
        return this;
    }
}

There are 2 types of parameters for this scenario: required (username and password) and optional with default values (language). The usage of fluent interface in setting up the scenario plays very nicely with the overall style of the integration tests. The fancy-looking generic Scenario interface allows to chain the execution of this reusable block of code in a fluent interface of the actual test:

public class LoginTest {
    @Test
    public void will_login_and_logout() {
        new LoginPage("http://localhost/myapp")
            .run(new LoginScenario("johndoe", "secret").language("german"))
            .logout();
    }
}

I hope this will help you keep your integration tests code DRY and maintainable!

Happy coding!

Tuesday, January 28, 2014

Writing selenium tests with style!

I know it's been more that a while sine I last blogged but there's actually a good reason for it: I've been reviving a legacy application sentenced to death by decommission for the better part of the last year. With success I might add :) Now everybody wants a piece of it - but that's not what I wanted to talk about...

During this exercise beside obvious technology updates like switching to Tomcat from a God forsaken version of some other application server and making the project actually compile in a continuous integration environment, yata yata yata,  I've fiddled a little bit with selenium tests to make them at least do a sanity check while doing all those naughty changes. In doing so I've realized that actually Selenium can be a real beauty if used properly.

Without further due let's jump into the meat!

The problem

Selenium tests are integration tests and they are hard to write and maintain

The solution

This is actually not so hard and if you structure your tests properly, apply some rules and enforce a couple of design decisions then writing those tests is actually extremely easy and fun!

Let's see how we can turn the beast into a beauty!

Originally the recipe that you get when you arrive to Selenium's getting started page presents you with the basics (and for a good reason): create the driver, navigate to a page, search for an element, interrogate the element for some information. This works really nicely if all you want to do is automate Google's search engine and nothing else.

If you want to build some structure around the pages you test the Page Object design pattern comes to the rescue. Unfortunately the original documentation fails to mention the @FindBy annotation which is crucial for making the code look good and perform as expected.

Let's take a look at the following: we have an application (a hello-world style one) that presents one heading on the page with the text "Hello, world!". To describe the page using the @FindBy annotation simply declare the field as a WebElement and annotate it with @FindBy(id = "greeting")

public class HomePage {
    @FindBy(id = "greeting")
    public WebElement greeting;
}

Now to initialize such a page object instantiate it as you'd normally do

HomePage page = new HomePage();

and later on use the PageFactory.initElements(driver, page) method to initialize a set of proxies to elements. The "proxies" element is crucial: they don't need to appear on the page up front and you get all the usual stuff like waiting for them to load absolutely for free! It's like magic - only better :)

The Problem

Applications have structure and I need to repeat lots of elements

The Solution

Applications have structure. Their individual pages are not disconnected from each other, each presenting a totally different content. Usually pages are contained in some form of layout that'll act as a common experience for the user. Luckily for us we have decided to describe pages as classes and classes can do ... inheritance!

Let's say the HomePage is of some system that has a layout with logout button for the users to take a leave if they get bored using it.

public abstract class ApplicationPage {
  @FindBy(id = "logout")
}

Next we declare our HomePage as before, only denoting the application structure using inheritance:

public class HomePage extends ApplicationPage {
    @FindBy(id = "greeting")
    public WebElement greeting;
}

And you instantiate it as usual:

HomePage page = new HomePage();
PageFactory.initElements(driver, page);

This way we're expressing an "is-a" relation between the layout page and the actual page: The home page is an application page. In Java 8 we'll be able to put some of the stuff directly into interfaces and have even more capability to construct pages from functional bits and pieces. Until now for most cases this is more than enough.

The Problem

My integration tests are unreadable because of all the fiddling with Selenium.

The Solution

This is actually a huge problem, not only with Selenium or any other integration/unit tests. At least in Unit tests we have the universal layout ("given/when/then" or if you're more a Microsoft type guy then it'd be "arrange/act/assert"). But what about integration tests? They are expected to have assertions in the middle, they are expected to manipulate our application in many ways and verify the state in the middle because that's what the user would do!

No worry! There's this perfect little design pattern called fluent interface that we can easily employ to nicely structure our tests and to have cool, reusable place for everything! Let's start with the description of the test we're about to write:

- the user navigates to the login page
- verify that the login prompt actually says "Username" and "Password"
- upon entering the proper credentials and clicking "Login" the user lands on the home page
- verify that the login succeeded by checking the page's header or some other element

I suggest you take the description and follow it to the letter using fluent interface which might look something like this:

public class LoginTest {
    @Test
    public void will_login_properly() {
        new LoginPage("http://localhost/myapp")
            .assertHasProperUsernameLabel()
            .assertHasProperPasswordLabel()
            .enterCredentials("johndoe", "secret")
            .clickLogin()
            .assertPageTitleIs("Welcome to this cool application!");
    }
}

As you can see I've deliberately shifted all the specifics to the page objects, including navigation which is especially neat if you're working in an IDE and if you already have a set of page objects to work with. That way the IDE will actually tell you what you can do after you have "executed" a particular action (clickLogin for example).

Constructing such page objects isn't anything extremely sophisticated. Let's take a look at the LoginPage:

public class LoginPage {
    private final WebDriver driver;

    @FindBy(id = "username")
    WebElement username;

    @FindBy(id = "username-label")
    WebElement usernameLabel;

    @FindBy(id = "password")

    WebElement password;

    @FindBy(id = "password-label")
    WebElement passwordLabel;

    @FindBy(id = "login-button")
    WebElement loginButton;

    public LoginPage(WebDriver driver, String url) {
        this.driver = driver;
        if (url != null && url.length() > 0) {
            driver.navigate().to(url);
        }
    }

    public LoginPage assertHasProperUsernameLabel() {
        Assert.assertEquals("Username:", usernameLabel.getText());
        return this;
    }

    public LoginPage assertHasProperPasswordLabel() { ... }


    public LoginPage enterCredentials(...) { ... }

    public HomePage clickLogin() {
        loginButton.click();
        return new HomePage(driver);
    }
}

As you can see the assertions are contextual and can be re-used at will in any test scenario. The same goes for any operation you'd normally run on pages like filling in the login form and clicking on the login button and you can reuse them as many times as you want. If you combine that with inheritance you'll get a extremely powerful way to describe your application in an object-oriented way. With the fluent interface you'll get a chance to exercise that model in a way that will not make your eyes bleed when you'll get back to the code to fix that one button's location that has moved and all of the sudden all integration tests are failing.

The Problem

My integration tests run every time I build the project using Maven and it takes to much time

The Solution

The solution lies in proper Maven project configuration. Maven has this nice idea of profiles. I'm using a profile called "integration-test" to actually run everything integration-test-related only if that profile is enabled.

It's quite a lot of XML as you can probably imagine so I've prepared an example project that demonstrates the configuration. The crucial part in all this is the configuration of surefire, failsafe and tomcat7 plugins. You can grab the example here. If you do a mvn clean install then no integration tests will get executed but with mvn clean install -Pintegration-test you'll see Tomcat starting for the duration of tests and all the Selenium tests executed against that it.

Epilogue

We've been using this way of writing unit tests with great success for more than a few months now. It works great if you have regular web applications (request/response) and adopting it to any dynamic pages isn't all that difficult mainly because the @FindBy annotation does such an amazing job of hiding the complexity of Selenium.

Happy integration testing!

Friday, October 4, 2013

The longest route

I found myself in need today to share my local installation with a co-worker so that he can test a massive memory optimization I made.

Unfortunately me working from office and a ton of infrastructure with firewalls and what not between us I was forced to come up with a kind of non-standard solution to make it work. Here's what I've done:

1. The application runs locally on Tomcat (using Maven's tomcat6 plugin so mvn tomcat6:run)
2. Local Apache installation forwards requests from port 81 to 8080
3. An ssh tunnel is made that forwards my local port 81 to a remote port 8080 on a machine in Amazon
4. That remote machine has haproxy installed with a certificate that forwards local ports 80 and 443 to 8080 effectively allowing the user to login to my local installation

To test this I've used another Linux machine at home to login to with X forwarding enabled to locally view a remote Google Chrome running and accessing my local installation.

How can you not love Linux for that?

Sunday, September 29, 2013

Removing executable bit from files

I don't want to bore you with the details but I've been looking for a nice solution for this problem for a very long time. Today I came across this post:

http://superuser.com/questions/234647/how-to-remove-executable-bit-recursively-from-files-not-directories

chmod -R -x+X *

And life's simple again :)

Thanks to Pabouk (whoever you are)! You made my day!

Friday, August 23, 2013

Why documentation doesn't matter?

Well, it's not really true, it does matter - just not post mortem. It does tell the developer what to do - sometimes even how to do it. It tells the tester how to test it. After the release it's no longer valid nor accurate for anyone to use. Wanna know why?

A simple case


Imagine for a second there's a new position you just stepped into. It's this glorious application that everyone keeps talking about on the 'net. You took a position in one of the teams because you were certain that this can't be wrong - people have been doing that for years so good established processes and a proper technical documentation will be accompanied by a proper introduction training - something to take the edge off from new hires.

Introductory shock


I mean, woooow!!! You just came to the office, suddenly you realize nobody knows who you are, nobody seems to care. People seem to be rushing for no apparent reason through the floors - it's nothing like the place you've envisioned. But that's ok, right? You came here to do the job so let's get that notebook and let's get this show on the road!

Still positive, still passionate, still a foreigner - but you feel this is your chance! In this company, in this corporation there are endless possibilities! Here you will shine!

The second disaster


Ok, so you finally know where you sit, you've got your shiny new notebook on your desk trying to figure out what you've been given, trying to get your familiar tools installed so that you can finally kick start that 'being a developer at ' dream come true.

First of all you don't get to install whatever you want on company's property. No no.. There are rules in place preventing you to utilize whatever power Today's software market has to offer (commercial or OpenSource) so you're kinda stuck with what your new employer has carefully selected for you. You keep telling yourself that it's just a matter of time, that chemistry doesn't happen over night and that you'll get used to it. Why wouldn't you?

Anyways,... There comes the big moment: you're getting the sources! Obviously it's all going to be professional, high quality, top-to-bottom properly designed and brilliantly described in a few pages of perfect documentation. Well.. Our heroes rarely live up to our expectations and my friend this ain't no different. Suddenly it looks like some soft-skill course is more important than getting things done (the famous 'complete this course by today midnight or you'll be terminated' email floating around). Product training is something nobody heard within this walls since the company grew from 7 enthusiast to 1300 employees most of which have better things to do than to sit here, with you and explain obvious things - that seems like a giant waste of time, right?

So you're a professional, right?


And so you've got the code, you've got all the tools you shall need, you have access to the password-protected Maven repository and by all means - let's get to hacking! Obviously we need to start that thing first on that shiny new piece of equipment to compensate the lack of documentation with a debugger session. But wait! What's that error during compilation? Does that look like a broken test? NO!!! It's the code in one of the core modules that a colleague from abroad committed a few moments ago - just forgot to add that new class to version control before and it just so happened it landed this way on your machine. No worries! This is a good version control system so people's email addresses are there to chase that person and to give 'em hell! And so you do:

Dear John,

I've tried compiling our solution a moment ago but it seems like the code you committed Today lacks one of the new classes. Can you please check what's missing? Thanks!

Best regards,
Francisco

One should thing that such an error like "code does not compile" would be spotted by some continuous integration environment where it's constantly tested to meed the high quality standards everyone talked about on the interview. It just so happens that the server CI is on went down 3 weeks ago and nobody noticed. Since everyone sat so far in the same room with nice flowers and A/C if John would commit the code with errors Sally would come over for a coffee and tell him to fix it. This time John is some 6000 miles away on another continent and just called it a day.

No worries - I'm a professional!


And so I'm capable of at least learning the inner workings of the system by going through that clear-cut set of unit and integration tests the project is obviously equipped with. So where are they?

The real life


As with any corporation there are rules: you don't moan, you be creative, think outside of the box, be proactive - and all that politely and politically correct. Following this path 2 weeks later you've got the application running, the database it talks to is across several VPN connections so it's ridiculously slow, most of the external systems don't respond since their security just isn't setup for your location (you being the new developer in the team abroad) and quite frankly you start to miss on the boss that told you you can go to hell because he's not going to be giving you anything you didn't earn with blood and sweat and tears.

So why doesn't documentation matter?


Plain and simple: if you think you have any form of documentation other than the application code itself you're mistaken. Anything talking about the code, telling you how things are is bullshit and does not mean a thing. Wanna know why? Because your compiler doesn't read wiki, it doesn't have access to your email account nor does he care at all about Word documents and Excel spreadsheets. All it's interested in is the funky looking wall of text in source files - that's the only specification, the only documentation, the only rule book that will tell you everything.

So for the love of God: KEEP IT CLEAN! You're gonna need it 'cause you're gonna read it over and over and over and over again. If your co-workers (co-located and those miles, miles away) don't understand the need for keeping things clean tell them it's important to you, that you don't want to work in manure.

And if they will not listen - to hell with them! Tell the world how things are so that the next person drown by the lucrative perspective of working in young and highly motivated team will stay away. Let other learn from your experience.

Post scriptum


If any of you felt this matches any of your previous experience I rush to say it's fiction (well at least some of it). The situation as a whole didn't happen at all (would have been a disaster and a case for a shrink afterwards :] ). It's just to underline the importance of clean code and the fact that the code is the ultimate documentation out there. Don't undermine it.