Monday, February 27, 2012

Lazy way on how to generate pretty huge set of distinct (unique) hex values

We sometimes need to generate huge set of quite short distinct identifiers. Another requirement is that the identifiers generated with the chosen method (despite of a huge generated set) are still from the much bigger set and actually represent a small subset of that (this for example could help when you generate the number which you would like is hard to guess. probably to generate the invites for your site).

Here is the lazy way on how to do that using java. Using it I generated 500K distinct hex values (8-digit in a maximum) from 4.3 bil total space in a few seconds. That means the user will have to try to guess the right value for approximately 9K times.

So.. this is the code

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;


public class Generator {
 
 public class DummyStringKeeper {
  
  String string;
  
  public DummyStringKeeper(String string){
   this.string = string;
  }
 }

 public static void main(String args[]) throws IOException{
  BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:/temp/items_expoted.txt"));
  ArrayList<DummyStringKeeper> list = new ArrayList<DummyStringKeeper>();
  for (int i=0; i<500000; i++){
   DummyStringKeeper randomItem = new Generator().new DummyStringKeeper(UUID.randomUUID().toString());
   list.add(randomItem);
   String randomItemString = randomItem.toString().substring(randomItem.toString().indexOf("@")+1) + "\n";
   bos.write(randomItemString.getBytes());
  }
  bos.flush();
  bos.close();
 }
 
}

Wednesday, February 15, 2012

Another view on how to simulate multi-user interaction in your Selenium 2 scenarios

I heard from a lot of people that the best pattern for keeping your web driver in the project is singleton. That looks doubtful. 
Since I got the requirement of multi-user interacting in my scenarios I used singleton pattern for webdriver and I had to use the following workflow for interaction
1. Log in with user A
2. Send message to user B
3. Log out with user A
4. Log in with user B
5. Handle the request from user A

That is not quite obvious and organic workflow. The much more convenient is to do something like this

1. Log in with user A
2. Send message to user B
3. Log in with user B
4. Handle the request from user A--- Finish the test or:
5. Log out with user A
6. Log out with user B

Add support for simultaneous work of several browsers

This cannot be implemented having singleton pattern as the one for your webdriver. This is my way of how to support several browsers simultaneously

First of all we need the factory to easily create new browser instances (aka new drivers)

 private static class WDFactory{
  public static WebDriver createWebDriver(Properties properties){
   String browser = properties.getProperty("browser");
   WebDriver driverToCreate;
   if(browser.toLowerCase().equals("*firefox")){
    driverToCreate = new FirefoxDriver();
   }else if(browser.toLowerCase().equals("*googlechrome")){
    driverToCreate = new ChromeDriver();
   }else{
    throw new UnsupportedOperationException("Not supported browser yet");
   }
   driverToCreate.get(properties.getProperty("domain"));
   driverToCreate.manage().timeouts().implicitlyWait(500, TimeUnit.MILLISECONDS);
   return driverToCreate;
  }
 }

Also we sure need the pool where we're going to store all the browser instances we're going to work with

public class WDPool {

 private HashMap<String, WebDriver> pool;
 
 public WDPool(){
  pool = new HashMap<String, WebDriver>();
 }
 
 public void closeDrivers(){
  for (String key: pool.keySet()){
   getDriver(key).close();
  }
 }
 
 public void addDriver(String id, WebDriver driver){
  ARTestCase.logger.debug("Adding driver with id [" + id + "]");
  driver.manage().deleteAllCookies();
  pool.put(id, driver);
 }
 
 public WebDriver getDriver(String id){
  ARTestCase.logger.debug("Returning driver with id [" + id + "]");
  return pool.get(id);
 }
}

Okay. Now you should consider your design. I have the class laying between the browser control engine (like selenium) and the business logic of the scenarios. So if you have one introduce the following method there. Otherwise introduce it into the class where your actual scenario is described

 public void pushDriver(String id){
  driver = WDFactory.createWebDriver(properties);
  stack.addDriver(id, driver);
 }

Here and after stack represents the instance of WDPool.

It will be used on the stage the new user is logging in.
and the facility to obtain the driver instance for the current user

 private WebDriver getDriver(){
  return stack.getDriver(ARTestCase.getCurrentUser());
 }

So now we're ready to instantiate the new browser each time the new user gets logged in. The browser instance is stored into the hashmap with the id holding the user's nick-name. There are only two things to do:

1. Change your log-in functionality of the scenario so that it requests pushDriver. In my case it has the following look:

    public void logIn(String username) throws ARAutomationException {
     getTestCase().getAdapter().pushDriver(username);
     getTestCase().setCurrentUser(username);
 // some actions to perform
    }

Where getTestCase().getAdapter() returns the interlayer of the test case we're currently executing holding all the stuff I'm writing here about.

2. Wherever  you used the pattern like driver.someMethod() you now should use getDriver().someMethod() described in two snippets above. That will make your framework to switch the browsers each time you either log in with new user or call

getTestCase().setCurrentUser(existingUserNameHoldingOneOfTheBrowserInstances);

For those who experience problems with Selenium 2 hovering

The common practice of simulating mouse hovering in Selenium 2 is to move the mouse cursor to the element located and wrapped with WebElement. This should look like this.
            Actions builder = new Actions(driver);
            builder.moveToElement(lookupXPathExists(xPath)).build().perform();
Where driver is your current WebDriver implementation and  lookupXPathExists(xPath) is a kind of procedure returning you the WebElement object by xPath (see my older posts for more details)

However a lot of people trying to apply such the approach for both FF and IE browsers experience the same issue: once your scenario tries to perform some next action after hovering (ex. click the button appeared after you have hovered the element) the hovering gets canceled.

So the only way for us is to wait until this issue is resolved. Use Chrome driver so far.. :)

Thursday, February 09, 2012

Selenium antipatterns or What is Selenium the worst for (or 'donts' for Selenium)

You probably know a lot of cases when selenium will help you a lot and will beat any competitor which means it is really the best solution on the market. However I'd like to share the set of the problems the selenium is better to put away from (selenium anti-patterns).

  • Prepare the base state. If you include the base state preparation procedures in your selenium-based framework, be ready you may get them failed which will cause the test fails as well. That will not mean your product functionality does not work in proper way. That will probably mean your base state generation procedure failed due to some instability which is certainly still the sort of seleniums feature combined with the specifics of http servers or network collisions :)
  • Run load testing. You definitely can simulate some load using the selenium just because you can simulate user's work flow with the help of it. Selenium drives the GUI browsers which consumes plenty of resources so even if you use HtmlUnit driver that won't help you much. More over the load generating framework supposes strong discipline of multi-threading beacuse if you have no such one, you may measure your own leaks aka the problems in your framework performance, not of your tested application's. Do not invent the wheel - use JMeter.
  • Accuracy testing. Once your web application delivers some analytics you probably will want to automatically check if the values in your tables are correct. That is bad practice for sure. Depending on your browser's locale the numbers may have different representation, so that is might cause the problems in string casting to number formats. The same is true for date and currency date types. Moreover you likely will have to maintain such the tests quite frequently due to HTML dynamic structure changes because in the most cases such the tables are drawn with the help of dedicated GUI framework which may vary the HTML representation slightly keeping GUI look unchanged for the user. And do not forget that being introducing accuracy assertions you will have to make sure your last assertion procedure matches the business logic of  the tested application
  • Third-party graphics testing like one provided by adobe flash, MS silverlight etc. Use dedicated products to test such the interactions
So those are the tings I'd not recommend to use selenium for. All other web testing stuff matches selenium capabilities pretty good.