Sunday 23 April 2017

Junit Listener for Unit Test cases - Its implementation with simple HTML Reporting

          Many of us already know that JUnit is a unit testing frame work and it is widely used by the developers to write the unit test cases. But most of the QAs would prefer to go with TestNG because of the more features offered by it. The main features of the TestNG are its Listeners and its own reporting. What if we could implement the listener with JUnit? What if we could implement the reporting with the help of that Listener? This makes the JUnit user's life easier.

Here is my attempt to do so. In this post We are going to learn about implementing the JUnit Listener and generating the HTML report with the help of that listener.

First of all, in your project, create a class called HTMLReport and paste the below code.

public class HTMLReport {
  public static String reportFileName = "unknown";
  public static int sNo=0;
  public static void createFolder(String strDirectoy) {
    boolean success = (new File(strDirectoy)).mkdirs();
    if (success) {
    }
  }
  public static void createHTMLTemplate(String environment, String strClassName) throws IOException {
    File tempFolder = new File("./junit");
    createFolder(tempFolder.getCanonicalPath().toString());
    reportFileName=tempFolder.getCanonicalPath().toString()+"//"+strClassName+"UnitTestReport.html";
    File file = new File(reportFileName);
    boolean blnCreated = false;
    try {
      blnCreated = file.createNewFile();
    } catch (IOException ioe) {
      System.out.println("Error while creating a new empty file :" + ioe);
    }
    System.out.println("Was file " + file.getPath() + " created ? : " + blnCreated);
    BufferedWriter writer = null;
    try {
      BufferedWriter bw = new BufferedWriter(new FileWriter(file));
      bw.write("<html><body>");
      bw.write("<title>Results</title>");
      bw.write(
          "</title><BODY bgcolor=White><TABLE BORDER=0 CELLPADDING=3 CELLSPACING=1 WIDTH=100%>");
      bw.write(
          "<table id=check1><TR COLS=2><TD WIDTH=20%></TD><TD WIDTH=10% align=Right><TD WIDTH=10% align=Right></TD></TABLE>");
      bw.write(
          "<br/><table border=\"0\" width=\"100%\" height=\"45\" border-spacing: 0px bgcolor=\"#728139\" style=\"font-family:Copperplate Gothic Bold; font-size:25px; color: #fffbbf;\"><tr height=\"21\"><td valign=\"center\" align=\"center\" width=\"80%\"><p align=\"center\" style=\"font-family: Copperplate Gothic Bold\"> Your Own Project Unit Test Execution Report</p></td></tr></table><br/><br/>");

      bw.write(
          "<table><TR COLS=4><TD BGCOLOR=#D8BFD8 WIDTH=5%><FONT FACE=VERDANA COLOR=Black SIZE=2><B> Project Name <DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=#00008B SIZE=2><B> Your Own Project <DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD  WIDTH=10%></TD><TD  WIDTH=10%></TD></TR>");
      bw.write(
          "<TR COLS=1><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=Black SIZE=2><B> Enviornment <DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=#00008B SIZE=2><B> "
              + environment
              + " <DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD  WIDTH=10%></TD><TD  WIDTH=10%></TD></TR>");
      bw.write(
          "<TR COLS=1><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=Black SIZE=2><B> User <DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=#00008B SIZE=2><B>"+ System.getProperty("user.name") +"<DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD  WIDTH=10%></TD><TD  WIDTH=10%></TD></TR>");
      bw.write(
          "<TR COLS=1><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=Black SIZE=2><B> Date&Time <DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD BGCOLOR=#D8BFD8 WIDTH=10%><FONT FACE=VERDANA COLOR=#00008B SIZE=2><B>"+ Utils.getCurrentDateTime("dd-MMM-yyyy hh:mm:ss.SSS") +"<DIV ALIGN=RIGHT></DIV></B></FONT></TD><TD  WIDTH=10%></TD><TD  WIDTH=10%></TR></TD></table>");

      bw.write("<table width=\"100%\"><TABLEBORDER=0 BGCOLOR=YELLOW CELLPADDING=3 CELLSPACING=1 WIDTH=20%>");
      bw.write(
          "<TR COLS=5><TD BGCOLOR=#993300 WIDTH=3%><FONT FACE=VERDANA COLOR=White SIZE=1><center><B> SNo </B><center></FONT></TD>");
      bw.write(
          "<TD BGCOLOR=#993300 WIDTH=30%><FONT FACE=VERDANA COLOR=White SIZE=1.5><B> TestCaseName <B/></FONT></TD>");
      bw.write(
          "<TD BGCOLOR=#993300 WIDTH=10%><FONT FACE=VERDANA COLOR=White SIZE=1.5><B> Status </B></FONT></TD>");
      bw.write(
          "<TD BGCOLOR=#993300 WIDTH=60%><FONT FACE=VERDANA COLOR=White SIZE=1.5><B> Failure Details </B></FONT></TD>");
      bw.close();
    } catch (IOException e) {
      System.out.println("Exception Occured" + e.getMessage());
    } finally {
      try {
        if (writer != null)
          writer.close();
      } catch (IOException e) {
      }
    }
  }

  public static void reportPass(String strTestCaseName, String strStatus ) {
    BufferedWriter bw = null;
    File file = new File(reportFileName);
    
    try {
      bw = new BufferedWriter(new FileWriter(file, true));
      bw.write(
          "<TR COLS=5><TD BGCOLOR=#FFE4C4 WIDTH=3%><FONT FACE=VERDANA COLOR=GREEN SIZE=1><center>"
              + sNo + "</center></FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=30%><FONT FACE=VERDANA COLOR=GREEN SIZE=1>" + strTestCaseName
          + "</FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=10%><FONT FACE=VERDANA COLOR=GREEN SIZE=1>" + strStatus
          + "</FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=60%><FONT FACE=VERDANA COLOR=GREEN SIZE=1>" + ""
          + "</FONT></TD>");
      bw.close();
    } catch (IOException e) {

    } finally {
      try {
        if (bw != null)
          bw.close();
      } catch (IOException e) {
      }
    }
  }

  public static void reportFail(String strTestCaseName, String strStatus, String strStackTrace) {
    BufferedWriter bw = null;
    File file = new File(reportFileName);
    try {
      bw = new BufferedWriter(new FileWriter(file, true));
      bw.write(
          "<TR COLS=5><TD BGCOLOR=#FFE4C4 WIDTH=3%><FONT FACE=VERDANA COLOR=RED SIZE=1><center>"
              + sNo + "</center></FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=30%><FONT FACE=VERDANA COLOR=RED SIZE=1>" + strTestCaseName
          + "</FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=10%><FONT FACE=VERDANA COLOR=RED SIZE=1>" + strStatus
          + "</FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=60%><FONT FACE=VERDANA COLOR=RED SIZE=1>" + strStackTrace
          + "</FONT></TD>");
      bw.close();
    } catch (IOException e) {

    } finally {
      try {
        if (bw != null)
          bw.close();
      } catch (IOException e) {
      }
    }
  }
  
  public static void reportIgnored(String strTestCaseName, String strStatus) {
    BufferedWriter bw = null;
    File file = new File(reportFileName);
    String strStackTrace="";
    try {
      bw = new BufferedWriter(new FileWriter(file, true));
      bw.write(
          "<TR COLS=5><TD BGCOLOR=#FFE4C4 WIDTH=3%><FONT FACE=VERDANA COLOR=RED SIZE=1><center>"
              + sNo + "</center></FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=30%><FONT FACE=VERDANA COLOR=BLUE SIZE=1>" + strTestCaseName
          + "</FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=10%><FONT FACE=VERDANA COLOR=BLUE SIZE=1>" + strStatus
          + "</FONT></TD>");
      bw.write("<TD BGCOLOR=#FFE4C4 WIDTH=60%><FONT FACE=VERDANA COLOR=BLUE SIZE=1>" + strStackTrace
          + "</FONT></TD>");
      bw.close();
    } catch (IOException e) {

    } finally {
      try {
        if (bw != null)
          bw.close();
      } catch (IOException e) {
      }
    }
  }
}
    In the above class, We are implementing the reporting part by using Java. We use the plain HTML tags to generate the report. This code creates a folder called "junit" in your project and report would be placed under it. You can modify these HTML tags and the text according to your project needs.

     Next, we are going to implement the JUnit listener by extending the RunListener class provided by JUnit. RunListener is a class, which hears all the events performed in your Unit test cases using JUnit. You can find more about RunListener below:

   Again here, I have implemented this custom listener class by considering report in mind. You can customize this class according to your project needs. Create a class called JUnitExecutionListener and paste the below code.

public class JUnitExecutionListener extends RunListener {
  public DomainUtils domainUtils = new DomainUtils();
  public static boolean blnFailed=false;
  
  @Override
  public void testRunStarted(Description description) throws Exception {
    HTMLReport.createHTMLTemplate("Your own env",description.getClassName().split("\\.")[description.getClassName().split("\\.").length-1]);
    System.out.println("Number of tests to execute: " + description.getMethodName());
  }

  @Override
  public void testRunFinished(Result result) throws Exception {
    System.out.println(result.getFailureCount());
    System.out.println("Number of tests executed: " + result.getRunCount());
  }

  @Override
  public void testStarted(Description description) throws Exception {
    HTMLReport.sNo=HTMLReport.sNo+1;
    blnFailed=false;
    System.out.println("Starting: " + description.getMethodName());
  }

  @Override
  public void testFinished(Description description) throws Exception {
    if(!blnFailed){
      HTMLReport.reportPass(description.getMethodName(), "Passed");
    }
    System.out.println("Finished: " + description.getMethodName());
  }

  @Override
  public void testFailure(Failure failure) throws Exception {
    blnFailed=true;
    HTMLReport.reportFail(failure.getDescription().getMethodName(), "failed",
     failure.getTrace());
    System.out.println("Failed: " + failure.getDescription().getMethodName());
  }

  @Override
  public void testAssumptionFailure(Failure failure) {
    System.out.println("Failed: " + failure.getDescription().getMethodName());
  }

  @Override
  public void testIgnored(Description description) throws Exception {
    HTMLReport.sNo=HTMLReport.sNo+1;
    HTMLReport.reportIgnored(description.getMethodName(), "Skipped");
    System.out.println("Ignored: " + description.getMethodName());
  }

}

      Now, We are going to implement the custom runner class. Then we use this runner class with the @RunWith annotation which will register our JUnit Listener to the test case. That code is as below

public class MyRunner extends BlockJUnit4ClassRunner {

    public MyRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    public void run (RunNotifier notifier){
        //Add Listener. This will register our JUnit Listener.
        notifier.addListener(new JUnitExecutionListener());

        //Get each test notifier
        EachTestNotifier testNotifier = new EachTestNotifier(notifier,
                getDescription());
        try {
            //In order capture testRunStarted method
            //at the very beginning of the test run, we will add below code.
            //Invoke here the run testRunStarted() method
            notifier.fireTestRunStarted(getDescription());
            Statement statement = classBlock(notifier);
            statement.evaluate();
        } catch (AssumptionViolatedException e) {
            testNotifier.fireTestIgnored();
        } catch (StoppedByUserException e) {
            throw e;
        } catch (Throwable e) {
            testNotifier.addFailure(e);
        }
    }
}

With this, we are done with the whole setup. Now write a class with sample Unit test cases as below:

@RunWith(MyRunner.class)
public class JunitSample {
  public DomainUtils domainUtils= new DomainUtils();
    @Test
    public void testListener(){

    }

    @Test
    public void testFalseAssertion(){
        assertTrue(false);
    }

    @Ignore
    @Test
    public void testIgnore(){

    }

    @Test
    public void testException(){
        throw new RuntimeException();
    }
}

         If you observe in the above class, I have used @Runwith annotation with my custom runner class. Now all the test cases would be executed via my runner implementation. If you run this class, you will get a report as below.

         This implementation would be very helpful, particularly when you have many cases to run. While executing these many cases, it is hard to track all the test cases. This implementation is also purely Java and simple HTML solution. 

        You can even use these reports with CI tools such as Jenkins. Jenkins has a plugin called htmlpublisher,  through which you can configure the reports. Below link would be useful if you want to configure that.

Thursday 6 April 2017

Builder Design Pattern in Java - Its uses in automation

          The builder pattern is an alternative way to construct complex objects. This should be used only when you want to build different immutable objects using same object building process. Builder pattern aims to Separate the construction of a complex object from its representation so that the same construction process can create different representations.

Why do we need Builder Pattern:
      We all know that constructors in java are used to create objects and takes the parameters that are required create them. The problem starts when we have lot of parameters and some of them may be mandatory and some are optional. 

    To illustrate the problem, lets take an example of ordering ice cream online. There are multiple varieties of the ice creams available currently in the market.Each person has different choices of toppings, flavors etc. Now consider that you are creating an object for each user's choice. In this case you will end up creating multiple constructors based each user's choice. Also, if you pass the value of one parameter to other parameter, the whole thing would mess up.

Problems:
1. Too many constructors
2. Error prone because of multiple parameters
3. The order has to be followed while creating the object.

Builder pattern solves all the above problems. Lets see an implementation example.

============================================================
public class BuilderPatternValidator {
  public static void main(String args[]) {
    // Creating object using Builder pattern in java
    IceCream MilkIceCream = new       IceCream.Builder().milk(1).chocochips(2).caramel(2).dryfuits(1.5).m_ms(0.75).build();
    IceCream SoyaIceCream = new IceCream.Builder().soya(1).peanuts(2).caramel(2).dryfuits(1.5).m_ms(0.75).build();

    // IceCream is ready to eat :)
    System.out.println(MilkIceCream);
    System.out.println(SoyaIceCream);
  }
}

class IceCream {
  private final double milk; // cup
  private final double soya; // cup
  private final int chocochips; // spoon
  private final int caramel; // spoon
  private final double peanuts; // cup
  private final double dryfuits; // spoon
  private final double m_ms; // cup
  private final int cherry; // number

  public static class Builder {
    private double milk; // cup
    private double soya; // cup
    private int chocochips; // spoon
    private int caramel; // spoon
    private double peanuts; // spoon
    private double dryfuits; // spoon
    private double m_ms; // cup
    private int cherry; // number

    // builder methods for setting property
    public Builder milk(double cup) {
      this.milk = cup;
      return this;
    }

    public Builder soya(double cup) {
      this.soya = cup;
      return this;
    }

    public Builder chocochips(int spoon) {
      this.chocochips = spoon;
      return this;
    }

    public Builder caramel(int spoon) {
      this.caramel = spoon;
      return this;
    }

    public Builder peanuts(int spoon) {
      this.peanuts = spoon;
      return this;
    }

    public Builder dryfuits(double spoon) {
      this.dryfuits = spoon;
      return this;
    }

    public Builder m_ms(double spoon) {
      this.m_ms = spoon;
      return this;
    }

    public Builder cherry(int number) {
      this.cherry = number;
      return this;
    }

    // return fully build object
    public IceCream build() {
      return new IceCream(this);
    }
  }

  // private constructor to enforce object creation through builder
  private IceCream(Builder builder) {
    this.milk = builder.milk;
    this.soya = builder.soya;
    this.chocochips = builder.chocochips;
    this.caramel = builder.caramel;
    this.peanuts = builder.peanuts;
    this.dryfuits = builder.dryfuits;
    this.m_ms = builder.m_ms;
    this.cherry = builder.cherry;
  }

  @Override
  public String toString() {
    return "IceCream { " + "milk=" + milk + ", soya=" + soya + ", chocochips=" + chocochips + ", caramel="
        + caramel + ", peanuts=" + peanuts + ", dryfuits=" + dryfuits + ", m_ms=" + m_ms
        + ", cherry=" + cherry + '}';

  }
}
=========================================================
Points to be noted from the above example are: 

  1. IceCream constructor is private, which means that this class can not be directly    instantiated from the client code. 
  2. While creating the objects, I have declared only the parameters that are needed
  3. The order of the parameters can be varied.
  4. Code looks more readable. 

Advantages:
1) more maintainable if number of fields required to create object is more than 4 or 5.
2) less error-prone as user will know what they are passing because of explicit method call.
3) more robust as only fully constructed object will be available to client.

Disadvantages:
1) verbose and code duplication as Builder needs to copy all fields from Original or IceCream class.

How to use this builder pattern in Automation:
      The builder pattern is very handy particularly in API automation, where we deal with large number of parameters. While creating the requests, we use pojo classes. This builder pattern can be used to construct the object with the required parameters and pass it to pojo classes. This way we can reduce lot of code duplication.