Thursday, July 28, 2011

isElementPresent in Selenium-2.0

Recently while going through Selenium-2.0 I found out that WebDriver does not have a function called isElementPresent(). This was one of the important functions that was used in Selenium-1.0. It was mainly used for waiting for an element to be available to take an action on it. To implement this in WebDriver you just need to write a method as mentioned below. You can then  use this function with any type of "By"(By.id, BY.name, etc.)


private boolean isElementPresent(WebDriver driver, By by){
  try{
   driver.findElement(by);
   return true;
  }catch(NoSuchElementException e){
   return false;
  }
 }
The above function will return true in case the element is found on the page, else it will return false. For ex. The above function can be used for implementing the waitForElementPresent function of Selenium-IDE as mentioned below.


for (int second = 0;; second++) {
   if (second >= 60) fail("timeout");
   try { if (this.isElementPresent(driver,By.linkText("Software testing - Wikipedia, the free encyclopedia"))) break;
   Thread.sleep(1000);
    } catch (Exception e) {}
  }



Monday, July 25, 2011

Sending an E-mail with your Test Execution Reports

While doing automation testing many of us had thought that it is good to send the excetuion report mail after your test execution. In this blog I am going to tell two ways using which you can send a mail with to multiple E-mail addresses with your execution report attached.

Using ant:
Ant supports a mail task which can be used as one of your ways for sending a mail. Following target can be used to send a mail using ant:



  
     
     
     
     The Test nightly build has completed
     
       
          
      
     
  



In the above target you need to mention the following things:
mailhost – this the sender host of your mail box. You can this from your outgoing configuration of account in you mail client. For gmail it is “smtp.gmail.com”

port – this is the port at which the above mailhost support sending of email. This configuration also you can check in your mailbox configuration. By default it is “25” but for SSL and TLS support it will be different for different hosts.

User/password – some mail hosts need the username and password of the account mail box to authenticate the user while sending a mail. You need to provide this in the “user” & “password” attributes.

ssl – if you want to use ssl for contacting the mailbox you need to set this attribute value to “true”



subject – Subject of the mail you want to give.

to – you need provide the address of the email recepients here using the “address” attribute. You use a property also here. This property you can setusing the properties file and then importing to the build.xml

attachments – this can be used to attach your report as part of the mail and then send it.

Please note: If you get a MIME error or java mail error while running the above target. Please download a jar of “java mail” and put it to the lib folder of your ant installation.

Using Java code:
When I had this problem of sending the execution report as mail, I did it in a hard way by writing the following java code. In the following code I had used the javax mail API for composing and sending the mail.

public void sendMessage(List<String> attachment)throws Exception{
Properties props = System.getProperties(); 
String host="SMTP_HOST";
String from="FROM_EMAIL";
String to="TO_EMAIL";
  // Setup a mail server
 
 //setting the host    
props.put("mail.smtp.host", host);
Session session = 
        Session.getInstance(props, null);

      // Define the mail message
      MimeMessage message = new MimeMessage(session);
//setting the from address      
message.setFrom(new InternetAddress(from));
//Creating an array of email addresses for sending the mail
      javax.mail.internet.InternetAddress[] addressTo = javax.mail.internet.InternetAddress.parse(to);

      for (int i = 0; i < addressTo.length; i++)
      message.addRecipient(Message.RecipientType.TO, addressTo[i]);
      //Setting the suject of the mail
      message.setSubject(
        "Automation TestSuite Report");

      // create the message part 
      MimeBodyPart messageBodyPart = 
        new MimeBodyPart();

      //fill message
      messageBodyPart.setText("Hi,\n\nAttached is the Automation TestSuite Report for Test application.\n\nRegards,\nAutomation Team");

      Multipart multipart = new MimeMultipart();
      multipart.addBodyPart(messageBodyPart);
      
      // The below secton is used to add attachments to the mail. A list String is sent with the apth of different files that needs to be attached.
      messageBodyPart = new MimeBodyPart();
      Iterator<String> itr = attachment.iterator(); 
      while(itr.hasNext()){
      messageBodyPart = new MimeBodyPart();
      String filename=itr.next().toString();
      DataSource source = new FileDataSource(filename);
      messageBodyPart.setDataHandler(new DataHandler(source));
      filename=filename.substring((filename.lastIndexOf("/"))+1);
      messageBodyPart.setFileName(filename);
      multipart.addBodyPart(messageBodyPart);
      }
      // Put parts in message
      message.setContent(multipart);

      // Send the message
      Transport.send( message );

 }

Thursday, July 21, 2011

Getting the width and height of an Image using Selenium

People has kept asking me how to capture the width and height of an image/element using selenium. I tried to get an answer to it and the solution is very simple. The solution comes with Selenium itself.

Selenium-1 consists of certain functions for storing element values like getElementHeight, getElementWidth, getElementPositionLeft, getElementPositionRight, getElementPositionTop.

Similarly in Selenium-2(WebDriver) you can use the getSize() function which will return a "Dimension" class object. You can then use the getHeight() and getWidth() functions over it for getting the width and height of the element.


We can use these functions to get the position of the element and also its width and height.
Following is an example for getting the height and width of an image/element on the browser using Selenium-1.



height = selenium.getElementHeight("location to the image on the browser.(xpath or id)")
width = selenium.getElementWidth("location to the image on the browser.(xpath or id)")



Following is an example for getting the height and width of an image/element on the browser using Selenium-2(WebDriver).


height = driver.findElement("location to the image on the browser.(xpath or id)").getSize().getHeight();
width = driver.findElement("location to the image on the browser.(xpath or id)").getSize().getWidth()



Wednesday, July 20, 2011

Comparing and re-sizing images using Selenium

While automating a web application some of us have to deal with the test to check that an image has been successfully uploaded or not.And that the uploaded image matches with the actual one or not. To automate this test, there are certain things that we need to achieve:

  1. Saving the image that has been uploaded for comparison with the original image.
  2. Handling the re-sizing and re-formatting of the image by the web application itself.
  3. Logic to compare images.

1. Saving the image.
Selenium does not support any direct way to actually store/get an image. But there are other ways like "right-click" and "Save as" option using which you can save the image on firefox and chrome. Once you get an image you can move further with the second step that is checking size of the image.

2. Handling the re-sizing and re-formatting of the image by the web application itself.
Whenever we upload an Image to a web-app it internally re-size and re-format the image while storing or rendering to save space and improve performance. So if you save an uploaded image from your web-app  and want to compare it with the original image, it will fail. The reason being the image that you had downloaded from the web-app has been modified and may not match with the original image in terms of format, size and clarity. The solution to it can be achieved by getting the logic from the development team for re-sizing or re-formatting of image that they use inside their code. You can use then use the same code in you automation test to re-size and re-format your original image and then compare it with the downloaded image to check whether both matches or not.
Following code will give you a general idea on how to re-size an image.

public BufferedImage resize(BufferedImage img, int newW, int newH) {
//Getting the width and height of the given image.  
int w = img.getWidth();
  int h = img.getHeight();
//Creating a new image object with the new width and height and with the old image type
  BufferedImage dimg = new BufferedImage(newW, newH, img.getType());
  Graphics2D g = dimg.createGraphics();
  g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
//Creating a graphics image for the new Image.
  g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null);
  g.dispose();
  return dimg;
 }

3. Logic to compare images.
Once you had completed the above two steps you can go ahead with comparison of the images.
Following is a  java code using which you can actually match two images pixel by pixel.


import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;


public void compareImage() {
  boolean ret = true;
  try {
   original = ImageIO.read(new File(
     "originalFile"));
   copy = ImageIO.read(new File("copyFile"));

   ras1 = original.getData();
   ras2 = copy.getData();
//Comparing the the two images for number of bands,width & height.
   if (ras1.getNumBands() != ras2.getNumBands()
     || ras1.getWidth() != ras2.getWidth()
     || ras1.getHeight() != ras2.getHeight()) {
      ret=false;
   }else{
   // Once the band ,width & height matches, comparing the images.

   search: for (int i = 0; i < ras1.getNumBands(); ++i) {
    for (int x = 0; x < ras1.getWidth(); ++x) {
     for (int y = 0; y < ras1.getHeight(); ++y) {
      if (ras1.getSample(x, y, i) != ras2.getSample(x, y, i)) {
     // If one of the result is false setting the result as false and breaking the loop.
       ret = false;
       break search;
      }
     }
    }
   }
   }
   if (ret == true) {
    System.out.println("Image matches");
   } else {
    System.out.println("Image does not matches");
   }

  } catch (IOException e) {
   System.out.println(e);
  }
 }

Monday, July 18, 2011

Running Selenium Tests on different browsers using Junit

Many people has asked me on how to run a test on different browsers using Junit without actually changing the value of browser after one test execution. For which I had always kept answering that it may not be possible with Junit. But recently while trying to find a solution for it I came across with the Parameterization option that is available with latest changes of Junit. This was not possible in earlier versions of Junit but now Junit has come up with lot of added options in the latest version of Junit 4.8. Following is a way by which you can execute your automation tests in multiple browsers without actually waiting to finish your tests and then passing the second browser value. See the example below:
import com.thoughtworks.selenium.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.List;


@RunWith(Parameterized.class)
public class TestGoogleBase extends SeleneseTestBase {
  
  private String browser;
  public TestGoogleBase(String browser){
   this.browser=browser;
  }
  
  @Parameters
   public static List data() {
    return Arrays.asList(new Object[][]{{"*chrome"},{"*googlechrome"}});
   }

  @Before
  public void setUp() throws Exception {
   selenium = new DefaultSelenium("localhost", 4444, browser, "http://www.google.co.in/");
   selenium.start();
  }

  @Test
  public void testUntitled() throws Exception {
   selenium.open("/");
   selenium.type("id=lst-ib", "testing");
   selenium.click("//input[@value='Google Search']");
   for (int second = 0;; second++) {
    if (second >= 60) fail("timeout");
    try { if (selenium.isElementPresent("link=Software testing - Wikipedia, the free encyclopedia")) break; } catch (Exception e) {}
    Thread.sleep(1000);
   }
   selenium.click("link=Software testing - Wikipedia, the free encyclopedia");
   for (int second = 0;; second++) {
    if (second >= 60) fail("timeout");
    try { if (selenium.isTextPresent("Software testing")) break; } catch (Exception e) {}
    Thread.sleep(1000);
   }
  
  }

  @After
  public void tearDown() throws Exception {
   selenium.stop();
  }
 

}

In the above class I am using the @RunWith(Parametrized.class) option that will tell Junit that this class is run as a parametrized class. A parameter value providing method is added to the class by denoting @Parameter annotation which returns a List< Object[]> array. This array consists of the browser names on which the test needs to be executed, like “*chrome”(Firefox) and “*googlechrome” in this case.
The constructor of the said class is modified to accept a “browser” string that is set when the said parameter function return the browser value.
This “browser” value is then used by the “setup” and inturn by the “Test” method while execution.

Friday, July 1, 2011

Factory Class in TestNg

There are many functions provided by TestNG and you can use them in different ways I will mention in this blog about the @Factory implementation.

@ Factory
A Factory will allow to create test dynamically. And whenever we define a Factory it should always return an object array “Object[]”. All the test methods under the Class object which is created and returned using the Factory method is automatically executed by the Factory method. For ex.
public class FactoryClass {

@Factory
public Object[] createTest(){
   Object[] res = new Object[3];
   for(int i=1;i<=3;i++){
   res[i-1]=new main.java.FactoryImplementation(i);
  }
   return res;
}
}


public class FactoryImplementation {
int c_instance;
public FactoryImplementation(int instance){
   this.c_instance=instance;
  }
@Test
public void printMethod(){
   System.out.println("Instance Num is "+ c_instance);
  }
}

Whenever you execute the above two classes together as a TestNg test, the Output will be as follows:
Instance Num is 1
Instance Num is 2
Instance Num is 3

You only have to execute the Class named “FactoryClass”. Test-NG will find the Factory method inside it and will execute it. For each loop inside the Factory method an object of FactoryImplementation Class is created. On creation of the FactoryImplementation object and Instance value is set using the constructor. While creation of FactoryImplementation object the Test-NG automatically searches for all the “Test” methods inside the FactoryImplementation class and add them to its test execution list.
Another thing for you to notice is that each object created have a unique “c_instance” value set while object creation and the same value is used in the “printMethod”.

The Factory method can be used in different ways. One of the case may be when you want to execute a certain number of test inside a class for different values that can increase or decrease based on a condition.
This can be achieved by creation of the object of test class based on the number of values.
In the above class I am creating the object of the FactoryImplementation class inside a "for" loop. In a similar way you can iterate the for loop for number of different values for which the test needs to be run. And then initializing the test class object with such values and returning the Object array after storing them in the array. Something like the following:
@Factory

public Object[] createInstance(){
ArrayList ar = new ArrayList< Object>();
Object[] res =null;
for(int i=1;i<=5;i++){
ar.add(new main.java.FactoryImplementation(i+10));
}
res= new Object[ar.size()];
res=ar.toArray();
return res;
}

In the above method I am initializing the ArrayList which is dynamic in nature so depending on the no. of iterations I can increase the Array size and then store the same to the Object array and return it for execution.