dimanche 29 septembre 2013

Gatling dynamic parameters example

It is very easy to create a stress test with Gatling when you know the parameters to send within each HTTP request. But sometimes you have to handle dynamic parameters and this is more complicated to manage.

A typical case where dynamic parameters are needed is when you are testing a page with a form protected with a CSRF protection, for example :

<form action="/deleteAccount" method="POST">
  <input type="hidden" name="login" value="jsebfranck"/>
  <input type="hidden" name="verificationToken" value="wQvhCLsPHVbKd9ANoOZTpBsXtVhpG0h3"/>
</form>

For each display of this form, the verificationToken parameter expected on the server side will be different. This protection against CSRF attacks allows to be sure that the POST request is send from a form generated by the website, and not from another website.

If you use the gatling recorder to display the form page then submit the form, it will generate the following test :

val scn = scenario("delete account")
      .exec(http("get delete account page")
        .get("/Account/Delete")
        .headers(headers_1))
      .exec(http("delete account")
        .post("/Account/Delete")
        .headers(headers_5)
        .param("verificationToken", "wQvhCLsPHVbKd9ANoOZTpBsXtVhpG0h3")
        .param("login", "jsebfranck"))

The problem with this test is that it always sends the same verificationToken parameter within the form. So if you launch it, it will failed because the verificationToken will be different from the expected verificationToken.

To resolve this problem you have to parse the page with the form in order to retrieve the verificationToken parameter and to send it within the form. To do that you can use two advanced features of gatling, the "session" and the "saving data" features :

val scn = scenario("delete account")
      .exec(http("get delete account page")
        .get("/Account/Delete")
        .headers(headers_1)
        .check(
          regex("""<input name="verificationToken" type="hidden" value="([^"]*)" />""")
          .saveAs("requestVerificationToken")))
      .exec(http("delete account")
        .post("/Account/Delete")
        .headers(headers_5)
        .param("verificationToken", "${requestVerificationToken}")
        .param("login", "jsebfranck"))

The check method allows to do operations on the result of the request. Here we apply a regex to get the content of the value attribute, then we save it in the requestVerificationToken variable with the saveAs method :

    .check(
      regex("""<input name="verificationToken" type="hidden" value="([^"]*)" />""")
      .saveAs("requestVerificationToken")))

Then we can reuse the requestVerificationToken variable to send it within the form :

    .param("verificationToken", "${requestVerificationToken}")

Now you are able to use dynamic parameters in a Gatling test. I hope this example will help you to bypass most of the constraints of a website. For further information on gatling advanced usages, please visit this page.

jeudi 26 septembre 2013

Keep your code simple with YAGNI

One key principle of success for a web site is its capacity to always improve itself with new features and to do it faster than its competitors. To achieve that, the IT team must be able to create features as fast as possible at the different phases of the realization : development, tests and deployment.

During the development phase, one axis to work faster is to always have the more simple, readable and modifiable code. Besides several practices well known like code review or refactoring, there is an important principle which is not very well known by developers : YAGNI. Before explaining this principle, let's see how could a developer work without YAGNI.

Scenario without YAGNI

A agile development team has in its backlog several features and only the three first features are absolutely mandatory before the deployment in production :
  • Creation of a user (must have)
  • User listing (must have)
  • Deletion of a user (must have)
  • Modification of a user (nice to have)
  • Search a user by login (nice to have)
A developer begins to work on the "Creation of a user example" feature. To do that he has to create the user interface, the business logic and the DAO layer.

When he creates the DAO layer, he adds a method "createUser" and then he directly creates several others methods : "getUsers", "deleteUser", "updateUser" and "searchUserByLogin". The developer did that because he is quite sure that these methods will be necessary for the four other features of the backlog.

public interface UserDao {
  public void createUser(User user);
  
  public void updateUser(User user);
  
  public void deleteUser(User user);
  
  public User searchUserByLogin(String login);
  
  public List getUsers();
}

Then specifications change

The three mandatory features are developed and pushed in production. 

Having directly the feedback of the use of these three features in production, the two remaining features specifications change :
  • Modification of a user : it is not necessary anymore to modify a user as it is easy to delete a user and to create a new one
  • Search a user by login by first name : is is finally better to search the user by his first name.

And the developer modifies the code

As it is not necessary anymore to modify a user, the method "updateUser" has been created for nothing. And as the user search must be done by the first name rather than by the user login : the searchUserByLogin method must be changed.

The developer still thinks that the "updateUser" method could be useful in the future, so he doesn't delete it. Moreover, he keeps the "searchUserByLogin" method and create a new method "searchUserByFirstName".

So finally in the DAO layer, we have six methods but only four methods are used :

public interface UserDao {
  public void createUser(User user);
  
  public void updateUser(User user); // useless
  
  public void deleteUser(User user);
  
  public User searchUserByLogin(String login); // useless
  
  public User searchUserByFirstName(String firstName);
  
  public List getUsers();
}

The main mistake the developer did is to add unnecessary code in his program because he was thinking it could be useful in the future. The second mistake he did is to don't clean his code after the specifications change.

Maybe you don't realize why these two methods can be a problem in your code. So try to imagine several developers doing this mistake every day : it will be quickly the mess in your code.

You Ain't Gonna Need It!

Based on the fact that we cannot know or guess the future needs of a software, the idea of YAGNI is to never add code or feature which is not immediately necessary.

More than avoid to have useless methods in the code, the main advantages of the YAGNI principle are :
  • Your code is smaller, so more simple 
  • You don't have to maintain unnecessary code so you win time when you refactore your code 
  • You don't have pieces of code which have never been tested in production and you don't risk to use it thinking it is working