How To Create a Jar for Selenium TestNg tests using Maven

Recently there was a request from the deployment team to run some GUI and API test in the production environment, and the deployment team wanted to make it as simple as possible. Since it was supposed to be deployed in multiple customer locations, and they don't want to configure the remote connections and accessibility for multiple locations across the globe. Their proposal was to give them some automated standalone tool and they run the selenium or API test and report us the test results.

In this post we'll see how to generate a jar and run TestNg tests from command line, using Maven.

1. Maven Plugin
The Maven plugin which we are interested is maven-assembly-plugin, with descriptorRef as jar-with-dependencies.
The entire pom.xml as below.
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>AutoTestFramework</groupId>  
      <artifactId>AutoTestFramework</artifactId>  
      <version>0.0.1-SNAPSHOT</version>  
      <dependencies>  
           <dependency>  
                <groupId>org.seleniumhq.selenium</groupId>  
                <artifactId>selenium-java</artifactId>  
                <version>3.0.1</version>  
           </dependency>  
           <dependency>  
                <groupId>org.testng</groupId>  
                <artifactId>testng</artifactId>  
                <version>6.10</version>  
                <scope>compile</scope>  
           </dependency>  
           <dependency>  
                <groupId>junit</groupId>  
                <artifactId>junit</artifactId>  
                <version>4.12</version>  
           </dependency>  
           <dependency>  
                <groupId>io.github.bonigarcia</groupId>  
                <artifactId>webdrivermanager</artifactId>  
                <version>1.5.0</version>  
           </dependency>  
           <dependency>  
                <groupId>com.sun.jersey</groupId>  
                <artifactId>jersey-client</artifactId>  
                <version>1.19.3</version>  
           </dependency>  
           <dependency>  
                <groupId>log4j</groupId>  
                <artifactId>log4j</artifactId>  
                <version>1.2.17</version>  
           </dependency>  
           <dependency>  
                <groupId>org.json</groupId>  
                <artifactId>json</artifactId>  
                <version>20160810</version>  
           </dependency>            
      </dependencies>  
      <build>  
           <pluginManagement>  
                <plugins>  
                     <plugin>  
                          <artifactId>maven-compiler-plugin</artifactId>  
                          <version>3.1</version>  
                          <configuration>  
                               <source>1.8</source>  
                               <target>1.8</target>  
                          </configuration>  
                     </plugin>  
                     <plugin>  
                          <artifactId>maven-assembly-plugin</artifactId>  
                          <version>3.0.0</version>  
                          <configuration>  
                               <descriptorRefs>  
                                    <descriptorRef>jar-with-dependencies</descriptorRef>  
                               </descriptorRefs>  
                          </configuration>  
                          <executions>  
                               <execution>  
                                    <id>make-assembly</id>  
                                    <phase>package</phase>  
                                    <goals>  
                                         <goal>single</goal>  
                                    </goals>  
                               </execution>  
                          </executions>  
                     </plugin>  
                     <plugin>  
                          <groupId>org.apache.maven.plugins</groupId>  
                          <artifactId>maven-surefire-plugin</artifactId>  
                          <version>2.16</version>  
                          <configuration>  
                               <suiteXmlFiles>  
                                    <!-- suiteXmlFile>testng.xml</suiteXmlFile-->  
                                    <!-- suiteXmlFile>suitestestng.xml</suiteXmlFile -->  
                               </suiteXmlFiles>  
                               <includes>  
                                    <include>**/Test*.java</include>  
                                    <include>**/*Tests.java</include>  
                                    <include>**/*Test.java</include>  
                                    <include>**/*TestCase.java</include>  
                               </includes>  
                          </configuration>  
                     </plugin>  
                </plugins>  
           </pluginManagement>  
           <plugins> <!-- jar with dependencies will NOT be generated without this, for #mvn package or install -->  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-assembly-plugin</artifactId>  
       </plugin>  
     </plugins>  
      </build>  
 </project>  

2. The project structure:
The screen-shot of my automation project as below.
Note that my test classes are in src/main/java folder, and not in src/test/java folder.

3. Generating the jar:
Right click the project in eclipse and do Maven Install or Package goal. You should see 2 jars created - one without dependencies and another with dependencies, under target folder.


4. Running the test classes:
Take the jar with dependencies to a separate location or system, and run as below.
 #java -cp AutoTestFramework-0.0.1-SNAPSHOT-jar-with-dependencies.jar org.testng.TestNG testng.xml  

The testng.xml should be in the same folder, and the running system should have same jdk version installed with which the jar was built.

Read More »

Generating SOAP webservice client stubs using Apache-CXF, Maven, Eclipse

How to create WSDL-first Java SOAP webservice client using CXF, Maven, and Eclipse.

Recently we wanted to build a Soap webservice client to invoke some operations in the production server. The client is supposed to be used by support staff and they have some determined set of operations to be performed on a daily basis. It turned out giving them a jar with command line options required for their operations.
In this post let me try to show how to generate the client stubs and invoke an operation. We will use CXF tool called wsdl2java to turn the WSDL into Java client code and Maven for dependencies and generating the code. We will use Eclipse as the IDE.

1. SOAP Service WSDL for our example:
For this example let us get the CDyne free GetStockQuote WSDL from here. You can right-click the link and save the WSDL to a location in your system.

2. Eclipse Maven Project and POM file:

  • Create a new Maven project in eclipse with artifactId as stockquote. See pom below for the options.
  • Place the downloaded WSDL at location stockquote/src/main/resources/
  • Add the maven dependencies and the required plugins as below.

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
      <modelVersion>4.0.0</modelVersion>  
      <groupId>com.sqadev</groupId>  
      <artifactId>stockquote</artifactId>  
      <version>0.0.1-SNAPSHOT</version>  
      <name>Stock Quote client</name>  
      <properties>  
           <cxf.version>3.1.7</cxf.version>  
           <java.version>1.8</java.version>  
      </properties>  
      <dependencies>  
           <dependency>  
                <groupId>org.apache.cxf</groupId>  
                <artifactId>cxf-rt-frontend-jaxws</artifactId>  
                <version>${cxf.version}</version>  
           </dependency>  
           <dependency>  
                <groupId>org.apache.cxf</groupId>  
                <artifactId>cxf-rt-transports-http</artifactId>  
                <version>${cxf.version}</version>  
           </dependency>  
      </dependencies>  
           <build>  
           <plugins>  
           <!--Generate Java stub from WSDL at build time -->  
                <plugin>  
                     <groupId>org.apache.cxf</groupId>  
                     <artifactId>cxf-codegen-plugin</artifactId>  
                     <version>${cxf.version}</version>  
                     <executions>  
                          <execution>  
                               <id>generate-sources</id>  
                               <phase>generate-sources</phase>  
                               <configuration>  
                                    <sourceRoot>${basedir}/generated/cxf/src/main/java</sourceRoot>  
                                    <wsdlOptions>  
                                         <wsdlOption>  
                                              <wsdl>${basedir}/src/main/resources/delayedstockquote.wsdl</wsdl>  
                                              <extraargs>  
                                                   <extraarg>-client</extraarg>  
                                                   <extraarg>-impl</extraarg>  
                                                   <extraarg>-verbose</extraarg>  
                                              </extraargs>  
                                         </wsdlOption>  
                                    </wsdlOptions>  
                               </configuration>  
                               <goals>  
                                    <goal>wsdl2java</goal>  
                               </goals>  
                          </execution>  
                     </executions>  
                </plugin>  
                <!-- Add the generated sources, this avoids having to copy generated sources to build location -->  
       <plugin>  
         <groupId>org.codehaus.mojo</groupId>  
         <artifactId>build-helper-maven-plugin</artifactId>  
         <version>1.12</version>  
         <executions>  
           <execution>  
             <id>add-source</id>  
             <phase>generate-sources</phase>  
             <goals>  
               <goal>add-source</goal>  
             </goals>  
             <configuration>  
               <sources>  
                 <source>${basedir}/generated/cxf/src/main/java</source>  
               </sources>  
             </configuration>  
           </execution>  
         </executions>  
       </plugin>  
           </plugins>  
           </build>  
 </project>  

  • If you get undefined element declaration exception, please refer here to fix it.
  • We use cxf-codegen-plugin to run wsdl2java to generate our Java code into ${basedir}/generated/cxf/src/main/java
  • In eclipse java code is generated using Maven generate-sources. Right click the project stockquote -> Run as -> Maven generate-sources.
  • On successful build the source files will be generated in the new folder /generated/cxf/src/main/java.
  • Four client are generated as DelayedStockQuoteHttpGet_DelayedStockQuoteHttpGet_Client, ...HttpPost_Client and ...Soap_Client, ...Soap12_Client version. See eclipse screenshot below:




3. Running the Client:
Now that we have the client code generate, let us try to check if it's working.
Update one of the client code to check if the request/response works fine.
Sample code after updating DelayedStockQuoteSoap_DelayedStockQuoteSoap_Client:

................
 DelayedStockQuote ss = new DelayedStockQuote(wsdlURL, SERVICE_NAME);  
     DelayedStockQuoteSoap port = ss.getDelayedStockQuoteSoap();   
     {  
     System.out.println("Invoking getQuote...");  
     java.lang.String _getQuote_stockSymbol = "VZ";  
     java.lang.String _getQuote_licenseKey = "0";  
     com.cdyne.ws.QuoteData _getQuote__return = port.getQuote(_getQuote_stockSymbol, _getQuote_licenseKey);  
     System.out.println("getQuote.result = " + _getQuote__return.getCompanyName());  
     System.out.println("getQuote.result.Verizon.lastTradeAmt = " + _getQuote__return.lastTradeAmount);  
     }  
     {  
     System.out.println("Invoking getQuoteDataSet...");  
     java.lang.String _getQuoteDataSet_stockSymbols = "";  
     java.lang.String _getQuoteDataSet_licenseKey = "";  
     com.cdyne.ws.GetQuoteDataSetResponse.GetQuoteDataSetResult _getQuoteDataSet__return = port.getQuoteDataSet(_getQuoteDataSet_stockSymbols, _getQuoteDataSet_licenseKey);  
     System.out.println("getQuoteDataSet.result=" + _getQuoteDataSet__return);  
     }  
................

In eclipse right click on the file and select "Run As" --> "Java Application".
Sample result as below:
 Nov 12, 2016 11:52:45 PM org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL  
 INFO: Creating Service {http://ws.cdyne.com/}DelayedStockQuote from WSDL: file:/C:/mysoftware/eclipse_wrkspce/stockquote/src/main/resources/delayedstockquote.wsdl  
 Invoking getQuote...  
 getQuote.result = Verizon Communications Inc. Com  
 getQuote.result.Verizon.lastTradeAmt = 46.69  
 Invoking getQuoteDataSet...  
 getQuoteDataSet.result=com.cdyne.ws.GetQuoteDataSetResponse$GetQuoteDataSetResult@9573584  
 Invoking getQuickQuote...  
 getQuickQuote.result=0  

Looks like our client is fetching results...
Src code in GitHub.
Next(in another post) we will see how we can build a jar with cmd line options to make some soap request/response.
Read More »

CXF wsdl2java - undefined element declaration 's:schema' - PluginExecutionException

Recently I got a third party generated wsdl, and when I try to use wsdl2java cxf-codegen-plugin in maven eclipse it shows the below error in the wsdl:

undefined element declaration 's:schema' (org.apache.cxf:cxf-codegen-plugin:3.1.7:wsdl2java:generate-sources:generate-sources)

After some googling it seems to be a common issue with JAXB and .NET WSDL.

Here is the problematic part of the WSDL:
 <s:element minOccurs="0" maxOccurs="1" name="GetQuoteDataSetResult">  
  <s:complexType>  
   <s:sequence>  
    <s:element ref="s:schema"/>  
    <s:any/>  
   </s:sequence>  
  </s:complexType>  
 </s:element>  

The easier solution seems to be to download the WSDL and modify the schema in order to generate the stub. Here is what I did to the WSDL as per the suggestion:
 <s:element minOccurs="0" maxOccurs="1" name="GetQuoteDataSetResult">  
        <s:complexType>  
         <s:sequence>  
          <!-- s:element ref="s:schema" /-->  
          <s:any minOccurs="2" />  
         </s:sequence>  
        </s:complexType>  
 </s:element>  

After the change the maven plugin ran successfully to generate the Java code.

Ref: http://cxf.547215.n5.nabble.com/Thrown-by-JAXB-undefined-element-declaration-s-schema-td554126.html
Read More »

Free Sample WSDL URL For WebService Testing

Here are some sample WSDL URL for web-services testing. This will be great help to people who want to try out SOAP web-services. The most popular tool for SOAP/Rest service testing is SoapUI, which is available for free. Download and try out some of the below URL's.

1. Global Weather: This global Weather is quite popular, and it will generate two request - GetCitiesByCountry and GetWeather. First try get the predefined cities by country and then do a get weather.
http://www.webservicex.net/globalweather.asmx?WSDL


2. Currency converter: Another simple service to start with. The inputs are string format like USD, GBP, INR, etc. Open the wsdl in a browser to see all the currencies allowed.
http://www.webservicex.com/CurrencyConvertor.asmx?wsdl


3. Get Stock Quotes: This has three API as below -
GetQuote: The result is current stock quote, with other information like DayHigh, DayLow, StockVolume, OpenAmount, etc.
GetQuickQuote: The result is just the stock price.
GetQuoteDataSet: Response is stock information in a dataset.
http://ws.cdyne.com/delayedstockquote/delayedstockquote.asmx?wsdl


4. City Weather by zip code, for US only. API's are GetCityForecastByZIP - get City Forecast Over the Next 7 Days, GetCityWeatherByZIP - get current City’s Weather.
http://wsf.cdyne.com/weatherws/weather.asmx?wsdl


5. Country Information Service: Not only information related to a country but lot of API's to work with including ListOfContinentsByName, ListOfCountryNamesByName, ListOfCurrenciesByCode, ListOfCountryNamesGroupedByContinent, etc. you can do a lot of test scenarios with this WSDL.
http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL

6. Number conversion: Simple API's with only 2 request - NumberToDollars and NumberToWords.
http://www.dataaccess.com/webservicesserver/numberconversion.wso?WSDL
Read More »

How To Manage Stress Positively

Please watch this amazing TED talk from psychologist Kelly McGonigal "How to make stress your friend".
The best way to manage stress is by embracing it, this is a really new idea which I am sure will help us all in this stressful world of today.

We are all aware of the power of thinking positively, but this astonishing talk takes us to the next level by making us believe that stress is indeed good for our health.
Her presentation style and most importantly the concept is mind boggling and I am already a fan or her.
Its less than 15 mins, just watch it without getting disturbed and de-stress yourself for life.

Read More »

Hi-Fi(WiFi) days ahead!!!

  WiFi has become very popular now a days, most of us use it at home, office, hotels and also at most public places like airports, stations where we can connect to public hotspots. It is built into most devices like mobile devices, laptops, tablets, etc. It wouldn't be too much to say that, if you haven't used a WiFi connection yet, then you are in minority.

A non-profit organization Wi-Fi Alliance, formed by a worldwide network of companies defines standards for interoperability of Wi-Fi device and promote the technology. WiFi or Wireless networking is based on the IEEE 802.11 standards. Starting with our smart phones, laptops, more and more devices are now coming up with WiFi capabilities, and with the arrival of IoT(Internet Of Things) we can expect more varieties of WiFi devices in near future. Experts estimate approximately 20 billion WiFi devices by 2017. One of the biggest advantage of WiFi is it is wireless just like our cell phone connection but WiFi comes with a better data speed and easy to set-up or connect.

  Connecting to a WiFi network would usually require a SSID password to be provided whenever a new SSID is encountered. This was causing a major hindrance to the wide acceptance of WiFi, unlike the cell phone service where a password is not required when roaming.
Now with the release of Hotspot 2.0(HS2) based on the IEEE 802.11u standard, a device can automatically connect to a WiFi network. The device is authenticated to the WiFi Access Point(AP) using credentials such as username/password, X.509 certificate with no intervention from the human user. This is very much like we connect to a mobile carrier’s 3G of 4G network while roaming and use services as if we are in our home network.
If a device is subscribed to a WiFi Hotspot 2.0 service with roaming agreement in place, then it will allow users to securely roam on a WiFi network, and with so many OTT(over-the-top) players like Skype or other VoIP services we might not even need a cellular connection to make a long distance call or chat.
Image Source: FreeDigitalPhotos.net

 Most cable MSOs(Multiple-System operators), Fixed-Line broadband service operators and others are trying to cash in on this huge revenue generating opportunity and might be cutting into mobile network operators(MNOs) customer base already. With the help of Wi-Fi Alliance's Hotspot 2.0 and other technology programs these operators are coming up with carrier WiFi services trying to make WiFi ubiquitous. Estimated approximately 50 million WiFi hotspots already deployed across the world, and we are going to see more deployments sooner than later.
Image Source: FreeDigitalPhotos.net

WiFi gives a good opportunity for these players as it is an unlicensed spectrum, almost all mobile devices have WiFi capability and also more than 90% of tablets are shipped with WiFi only connection. Most devices going ahead will also support WiFi calling, for e.g. Apple iPhone 6 already supports Wi-Fi calling as well as voice over LTE (VoLTE).
Image Source: FreeDigitalPhotos.net

Taking advantage of their existing network, cable MSO's have started to deploy public WiFi network with HS2 technology. Google is already working on building a large-scale WiFi network with devices from Ruckus Wireless.

Cable MSOs and fixed-line operators are going to allow service or network sharing with MNOs or themselves for their customers which would allow an user to connect where Wi-Fi Access Points(AP) isn't available. Several big MSO already announced sharing Wi-Fi network under a new alliance called "CableWiFi", which would allow users access to Wi-Fi outside their home network. With the same Wi-Fi network available at home and outside, this is going to give users a really good alternative to cellular service and with an excellent customer experience.
Image Source: FreeDigitalPhotos.net
Read More »

Internet Of Things(IoT) and the Broadband Forum TR-069

Of-late I haven't written much, as I switched jobs few months back, and have been too busy learning, exploring new waters. Don't know, but starting to feel the same in the new environment, already ;)
In this post, lets try put something related to the Broadband Forum TR-069 CPE WAN Management Protocol, as I have been working in this domain long enough and never got a chance to write something on this topic. Basically lets see what Broadband Forum(BBF) is doing about "Internet Of Things" or IoT which is the future of Internet as experts say.

Very brief intro of TR-069:
Technical Report 069(TR-069) is a specification from Broadband Forum(BBF) also called CPE WAN Management Protocol (CWMP), has been around for more than a decade. The protocol defines standard for communications between customer-premises equipment (CPE) devices, such as modems, gateways, set-top boxes, VoIP phones; and the Auto Configuration Servers (ACS). The protocol is mainly used for for automatic configuration and management of these CPE by an ACS. And it has been very successful in doing that, as we are already seeing nearly 300 million devices managed worldwide and it is still growing. The protocol which was earlier mostly used for DSL modems is now adopted by cable operators to manage cable modems.


As we all know, the current buzz in the market is about Internet Of Things(IoT) and how it will change our environment and lives. Experts estimates that there would be an upwards of 20 million devices connected by year 2020. The Consumer Electronics Show(CES) 2015 was mostly about the IoT smart devices which can communicate/talk with other devices like smartphones. Well there are already devices in market worldwide for e.g. smart TV, which can already communicate with smartphones. In the very near future, we are going to see more other devices like smart watches, smart-thermostats, smoke detectors, HealthKits and smart home devices.

With the ever evolving technologies, and now the advent of the IoT devices in our home environment there has been a continuous need for developing the TR-069 protocol. BBF has always been ahead on this and apart from releasing other technical reports like TR-181, etc, time to time, we have the latest TR-069 at Amendment-5.  Now it should be able to leverage its success and encompass the IoT device management, in order to catch up with the modern trend. As per the latest(17/June/2015) newsletter from BBF, they have been adding new features/improvement in TR-069 to support deployment and management of IoT devices. Well it will be really interesting to see the outcome, as this might be a win-win situation for the consumers and the telecommunication operators. Consumers with TR-069 CPE's will have their smart IoT devices managed by the same telecommunication providers. And telecom providers would be happy to oblige :)
Also, as per the 12th June 2015 press release, TR-069 is going to play an important role in IoT market and most service providers look forward to it.

Other than that, BBF also is working towards a new service platform  for activating, managing, monitoring, diagnosing, and controlling network enabled services. The protocol and models, including the implementation guidelines and other materials expected to be delivered by Q2 2016. That's next year, cheers!!!

About the Broadband Forum
Broadband Forum, a non-profit industry organization, is focused on engineering smarter and faster broadband networks. Our work defines best practices for global networks, enables service and content delivery, establishes technology migration strategies, engineers critical device & service management tools, and is key to redefining broadband. Our free technical reports and white papers can be found at www.broadband-forum.org. Twitter @Broadband_Forum.

Source: The Broadband Forum
https://www.broadband-forum.org/
http://www.broadband-forum.org/marketing/newsletter/June15.pdf
https://www.broadband-forum.org/news/download/pressreleeases/2015/BBF_Q2_2015_FINAL_12June2015.pdf
https://www.broadband-forum.org/news/download/pressreleeases/2014/BBF_Q2meeting_TR-069_FINAL_25June2014.pdf
Read More »

BDD Cucumber - Might Not be for a regular QA!

BDD Cucumber used with Selenium seems to be quite popular now a days for Automation framework. We have been using a BDD framework with Selenium for our Automation including Integration Tests. The tests are being added by the test team and dev team and they are run as part of build process(CI).
Though it is good that everybody, starting from the customer to the higher executives can read the tests, as the steps are written in (simple?) human understandable language - Gherkin, but BDD has its own limitations. Here are a few of the drawbacks that we encountered during our journey:

1. Steep Learning curve: A QA member is not a programming expert, else he should be in development. In our test team we had a mix of Java programmer(basic) and non-programmers. We really had a tough time explaining about Cucumber BDD to the non-programmers, and they still are not able to write tests properly. Imagine a non-programmer, who never has written a piece of code has to learn Java, Selenium, Cucumber and the BDD style of writing tests. Instead he could have simply learnt Java, Selenium and start adding tests with TestNG. In TestNG or Junit you don't need to worry about Given/When/Then. As for the programmer they still make mistakes writing proper Given/When/Then.

2. Translating test cases to BDD "scenario" is not fun: When we started automating, we already had more than 2000 odd testcases for our product, and those are not written thinking of BDD. We had to update/edit the test steps, split  testcases, carve out new steps to be inline with BDD. This is a huge overhead, we had to spend a considerable amount of time on this. Also when we write a new testcase we might actually think in plain English and not in BDD style. Writing testcases with BDD mindset is something which will come with good experience.
Again convention says, when we create a new step in Cucumber, we should make it generic in order to to be re-usable. With this in mind, we try to group similar tests in one "Feature" file. Again an overhead, scanning though different testcases to pick the similar ones. We have to do this because the less the files the better, and then people don't expect to write one "Feature" file for each testcase.

3. Limited Annotations as compared to other frameworks(TestNg, Junit): Cucumber has "Hooks" like @Before, @After. These are called for each "Scenario" from the "Feature" file. Annotations like @BeforeClass, @AfterClass, @BeforeSuite, etc from TestNg are not available in Cucumber. We know this could be achieved in Cucumber with "Runtime.getRuntime().addShutdownHook...", but wouldn't it be better if something is available out of the box? Also what about parallel test execution, of-course we can do this with Selenium, but TestNG and Junit already has this option compared to Cucumber.

4. The Gherkin is not-so-simple to be understood by stakeholder/customers: The Given-When-Then are usually written by technical person either test or dev member. Now our customer is a non-technical, business person who might not think the way as a technical guy. This itself defeats the main purpose of Cucumber that the stakeholder can read and understand Cucumber language. Also how many people other than a QA guy, cares about test steps. Unless there is some critical customer issue, nobody wants to go through the test steps in detail, even a developer have to be reminded multiple times to review a testcase.
Now for argument sake, lets say our customer is a technical person. How likely is it that he knows BDD Steps? Is he going to learn cucumber-BDD for reviewing your tests? Not yet, until he is forced upon :).

5. DuplicateStepDefinitionException seems to occur often: We have been seeing this often times. This occurs when we have duplicate methods in different class files and its likely to occur as different testcases have similar steps. Best solution to avoid this is to checkout all tests and run it locally before committing yours. The problem is people doesn't follow the solution, out of laziness or are in a hurry to automate more :).

Finally, saying all this drawbacks does-not mean that we are stopping with Cucumber. We are loving every bit of it and with each and every issue we are happy we learnt something new today. After all we are engineers and we keep learning!!!
Read More »

About Oracle NULL value

In a Database table if a column has no value, then the column is said to be NULL. It could be said as a place-holder where the database does not have any information about the value. It represents nothing, not a space, not a zero(0), nor a blank value.

1) A null value is not equal nor unequal to another null, i.e. can't use operators like "=" or "!=". Though, Oracle considers two nulls to be equal when evaluating a DECODE function. NULL values can be only tested with IS NULL and IS NOT NULL conditional operator.
hr@ORA10G> SELECT * FROM test_table ORDER BY id;
        ID COL1       COL2             COL3
---------- ---------- ---------- ----------
         1 KA         blr               100
         2            del
         3
         4 MAH                          400

hr@ORA10G> SELECT * FROM test_table WHERE col3 = NULL;
no rows selected

hr@ORA10G> SELECT * FROM test_table WHERE col3 IS NULL;
        ID COL1       COL2             COL3
---------- ---------- ---------- ----------
         2            del
         3

hr@ORA10G> SELECT * FROM test_table WHERE col3 IS NOT NULL;
        ID COL1       COL2             COL3
---------- ---------- ---------- ----------
         1 KA         blr               100
         4 MAH                          400

2) An expression containing a null value always returns a null value. For e.g. arithmetic expression containing a null value always results to null.
For e.g. 25+null will give result as null.
hr@ORA10G> select * from test_table order by id;
        ID COL1       COL2             COL3
---------- ---------- ---------- ----------
         1 KA         blr               100
         2            del
         3
         4 MAH                          400

hr@ORA10G> select col3+300 from test_table where id=2;
  COL3+300
----------


hr@ORA10G> select col3+300 from test_table where id=1;
  COL3+300
----------
       400

3) Most aggregate function like AVG(), COUNT(), ignore null values.
hr@ORA10G> select * from test_table order by id;
        ID COL1       COL2             COL3
---------- ---------- ---------- ----------
         1 KA         blr               100
         2            del
         3
         4 MAH                          400

hr@ORA10G> select avg(col3) from test_table;
 AVG(COL3)
----------
       250

hr@ORA10G> select count(col3) from test_table;
COUNT(COL3)
-----------
          2



4) The NULL values in the column sort as the highest value by default.
hr@ORA10G> select * from test_table order by col3 desc;
        ID COL1       COL2             COL3
---------- ---------- ---------- ----------
         2            del
         3
         4 MAH                          400
         1 KA         blr               100

5) The functions REPLACE, CONCAT, DECODE, NVL, NVL2 returns non-null values when invoked with a null argument. Most others scalar functions returns null with a null argument.
Both NVL() and NVL2() function replace null values with a specified value.

NVL(exp1, exp2) - This returns exp2 if exp1 is null, else return exp1. Both exp1 and exp2 should be of same datatype or it must be possible to implicitly convert exp2 to the type of the exp1.
hr@ORA10G> SELECT NVL('abc','xyz') FROM dual;
NVL
---
abc

hr@ORA10G> SELECT NVL(null,'xyz') FROM dual;
NVL
---
xyz

hr@ORA10G> SELECT NVL(123,'xyz') FROM dual;
SELECT NVL(123,'xyz') FROM dual
               *
ERROR at line 1:
ORA-01722: invalid number
The last example above is an error because 'xyz' cannot be converted to a number.

NVL2(exp1, exp2, exp3) - If exp1 is null then returns exp3, else return exp2. The datatypes of exp2 and exp3 must be compatible, or it must be possible to convert exp3 to the type of the exp2.
hr@ORA10G> SELECT NVL2('aaaa','bbbb','cccc') FROM dual;
NVL2
----
bbbb

hr@ORA10G> SELECT NVL2(null,'bbbb','cccc') FROM dual;
NVL2
----
cccc

hr@ORA10G> SELECT NVL2(null,'bbbb',1234) FROM dual;
NVL2
----
1234

hr@ORA10G> SELECT NVL2(null,1234,'cccc') FROM dual;
SELECT NVL2(null,1234,'cccc') FROM dual
                      *
ERROR at line 1:
ORA-01722: invalid number
The last example above is an error because 'cccc' cannot be converted to a number, whereas in the previous example it is possible to convert value "1234" to a varchar2 type.

Ref: http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements005.htm
Read More »

TestNG Data Provider - Data Driven Automation Testing

TestNg DataProvider is used for Data Driven testing in a Test Automation Framework. As the name implies DataProvider supplies data to our test methods. It helps us to execute a single test method with multiple sets of data.
DataProvider can also be used for getting data from file or database and passing to our test methods, we will see that in another post.

A DataProvider is a method of our class that must returns an array of array of objects(object[][]). This method is supposed to be annotated with @DataProvider and a 'name' attribute.
In our test method with @Test annotation, we specify the DataProvider with the 'dataProvider' attribute with a name that corresponds to our 'name' attribute in the DataProvider method.

The DataProvider method is usually defined and looked up in the same class as the test method. But we find it more helpful if we define it in another class, in that case it needs to be a static method. If we define DataProvider in a separate class, we specify the class name with 'dataProviderClass' attribute in our @Test annotation. See example (1) below.

A DataProvider method can return one of the follwing:
- An array of array of objects(Object[][]) where the first dimension's size is the number of times the test method will be invoked and the second dimension size contains an array of objects. The second dimension's array is what we define as parameter in our test method and must be compatible with the parameter types of the test method. See example (1) below for more clarity.
- An Iterator <Object[]>. The java.util.Iterator used in here lets us create our test data lazily. If we have a lot of parameter sets to pass to the method and we don't want to create all of them upfront, which is done incase we are using double array Object, we should use an Iterator. TestNg allows us to use an Iterator on the DataProvider so that the set of parameters are instantiated and returned when the test method gets invoked each time. This is called lazy initialization, and the idea is to create an object when required and not before. Example (5) below.

Here we will see a few examples using DataProviders. Just to make this post solely for TestNg DataProviders, we have not included any Selenium code here.

1) Lets start with passing simple parameters - we will pass 2 parameters in one test method and 3 parameters in another test.
We will define the DataProvider method in separate class.
package com.testng.test;
import org.testng.annotations.DataProvider;

public class Providers {
	@DataProvider(name = "provider1")
	public static Object[][] provideData() {
		return new Object[][] { 
			{ 1, 100 }, 
			{ 5, 500 }, 
			{ 10, 1000 } 
		};
	}
	
	@DataProvider(name = "provider2")
	public static Object[][] provideSomething() {
		return new Object[][]{
				{1,"Delhi","DEL"},
				{2,"Mumbai","MAH"}
		};
	}
}

The class which uses the providers:

package com.testng.test;
import org.testng.annotations.Test;

public class CheckDataProvider {
	
	@Test(dataProvider = "provider1", dataProviderClass = Providers.class)
	public void testData1(int inNum, int expect) {
		System.out.println("Number: " + (inNum * 100) + " Expected: " + expect);
	}

	@Test(dataProvider = "provider2", dataProviderClass = Providers.class) 
	public void testData2(int cityId, String city, String state) {
		System.out.println("City Id: " + cityId + " City: " + city + " State: " + state);
	}
}


Run the CheckDataProvider class as TestNG Test. Below is the output:
[TestNG] Running:
  C:\Users\sarats\AppData\Local\Temp\testng-eclipse--714784067\testng-customsuite.xml

Number: 100 Expected: 100
Number: 500 Expected: 500
Number: 1000 Expected: 1000
City Id: 1 City: Delhi State: DEL
City Id: 2 City: Mumbai State: MAH
PASSED: testData1(1, 100)
PASSED: testData1(5, 500)
PASSED: testData1(10, 1000)
PASSED: testData2(1, "Delhi", "DEL")
PASSED: testData2(2, "Mumbai", "MAH")

===============================================
    Default test
    Tests run: 5, Failures: 0, Skips: 0
===============================================

===============================================
Default suite
Total tests run: 5, Failures: 0, Skips: 0
===============================================
We see that each of the test method is run the number of times in our Object[][] array.


2) Passing a List: Returning a List from the DataProvider is usually done when we read input data from a file and DataProvider is used to pass on the data to the test method. Method for reading data from files are better placed in another class and then from within the DataProvider method we can just call the method.
We can iterate over the list in the DataProvider method(e.g. listProvider2) and return an Object[][], or we can pass on the List to the test method.
Below we will see both the ways, for the test method "listTesting1" we are just populating a List in the DataProvider method(listProvider1) and passing the list to the test method. We can also pass other collection objects like maps.
For test method "listTesting2" it is getting values from DataProvider(listProvider2) one at a time. Here the DataProvider method takes care of iterating over the list, which is usually the way we read data from a file and DataProvider passes on the data to test method one after another.
 package com.testng.test;  
 import java.util.ArrayList;  
 import java.util.List;  
 import org.testng.annotations.DataProvider;  
 import org.testng.annotations.Test;
 
 public class ListDataProvider {  
      @DataProvider(name = "listProvider1")  
      public static Object[][] provideListData() {  
            List<String> list = new ArrayList<String>();  
           for (int i=1; i<=5; i++) {  
                list.add("data" + i);  
           }  
           return new Object[][] { { list } };  
      }  
 
     @DataProvider(name = "listProvider2")  
      public static Object[][] provideListData2() {  
            List<String> list = new ArrayList<String>();  
           for (int i=1; i<=5; i++) {  
                list.add("data" + i);  
           }  
           String[][] ret = new String[list.size()][];  
           for (int i=0; i<list.size(); i++) {  
                ret[i] = new String[]{list.get(i)};  
           }  
           return ret;  
      }  

      @Test(dataProvider = "listProvider1")  
      public void listTesting1(List<String> list) {  
           System.out.println("#### " + Thread.currentThread().getStackTrace()[1].getMethodName() + " ####");  
           for (String str : list) {  
                System.out.println(str);  
           }  
      }  

      @Test(dataProvider = "listProvider2")  
      public void listTesting2(String str) {  
           System.out.println("#### " + Thread.currentThread().getStackTrace()[1].getMethodName() + " ####");  
           System.out.println("test data: " + str);  
      }  
 }  

Run the ListDataProvider class as TestNG Test, and below is the output:
[TestNG] Running:
  C:\Users\sarats\AppData\Local\Temp\testng-eclipse-788397593\testng-customsuite.xml

#### listTesting1 ####
data1
data2
data3
data4
data5
#### listTesting2 ####
test data: data1
#### listTesting2 ####
test data: data2
#### listTesting2 ####
test data: data3
#### listTesting2 ####
test data: data4
#### listTesting2 ####
test data: data5
PASSED: listTesting1([data1, data2, data3, data4, data5])
PASSED: listTesting2("data1")
PASSED: listTesting2("data2")
PASSED: listTesting2("data3")
PASSED: listTesting2("data4")
PASSED: listTesting2("data5")

===============================================
    Default test
    Tests run: 6, Failures: 0, Skips: 0
===============================================

===============================================
Default suite
Total tests run: 6, Failures: 0, Skips: 0
===============================================


3) Provide data depending on the calling test method: If same DataProvider is used to supply data to several test methods we can use "java.lang.reflect.Method" and provide data according to the calling method. DataProvider method can take a java.lang.reflect.Method as first parameter, in this case TestNG will pass the calling test method for this first parameter.
 package com.testng.test;
  
 import java.lang.reflect.Method;  
 import java.util.ArrayList;  
 import java.util.List;  
 import org.testng.annotations.DataProvider;  
 import org.testng.annotations.Test;  

 public class DataProviderMethodParam {  
      @DataProvider(name = "ProviderMethodParam")  
      public static Object[][] provideListData(Method method) {  
            List<String> list = new ArrayList<String>();  
           for (int i=1; i<=5; i++) {  
                list.add("data" + i);  
           }  
           if (method.getName().equals("listTesting1")) {  
           return new Object[][] { { list } };  
           }  
           else if (method.getName().equals("listTesting2")){  
                String[][] ret = new String[list.size()][];  
                for (int i=0; i<list.size(); i++) {  
                     ret[i] = new String[]{list.get(i)};  
                }  
                return ret;  
           }  
           return null;  
      }  

      @Test(dataProvider = "ProviderMethodParam")  
      public void listTesting1(List<String> list) {  
           System.out.println("#### " + Thread.currentThread().getStackTrace()[1].getMethodName() + " ####");  
           for (String str : list) {  
                System.out.println(str);  
           }  
           System.out.println("**********************************");  
      }  

      @Test(dataProvider = "ProviderMethodParam")  
      public void listTesting2(String str) {  
           System.out.println("#### " + Thread.currentThread().getStackTrace()[1].getMethodName() + " ####");  
           System.out.println("test data: " + str);  
      }  
 }  

Run the class DataProviderMethodParam as TestNG Test, and below is the output:
[TestNG] Running:
  C:\Users\sarats\AppData\Local\Temp\testng-eclipse--1473820315\testng-customsuite.xml

#### listTesting1 ####
data1
data2
data3
data4
data5
**********************************
#### listTesting2 ####
test data: data1
#### listTesting2 ####
test data: data2
#### listTesting2 ####
test data: data3
#### listTesting2 ####
test data: data4
#### listTesting2 ####
test data: data5
PASSED: listTesting1([data1, data2, data3, data4, data5])
PASSED: listTesting2("data1")
PASSED: listTesting2("data2")
PASSED: listTesting2("data3")
PASSED: listTesting2("data4")
PASSED: listTesting2("data5")

===============================================
    Default test
    Tests run: 6, Failures: 0, Skips: 0
===============================================

===============================================
Default suite
Total tests run: 6, Failures: 0, Skips: 0
===============================================


4) Provide data depending on ITestContext: We can use 'org.testng.ITestContext' in the DataProvider method to determine the runtime parameters of the calling test method. Depending on the parameter we can choose what data to provide. Here we will see how to pass data depending on TestNg's 'groups' attribute.
 package com.testng.test;  
   
 import java.util.Arrays;  
 import org.testng.ITestContext;  
 import org.testng.annotations.DataProvider;  
 import org.testng.annotations.Test;  
   
 public class DataProviderITestContext {  
    
  @DataProvider(name = "dpContext")  
  public Object[][] provided(ITestContext context) {  
   Object[][] result = null;  
   int numTimes = 5;  
   String[] groups = context.getIncludedGroups();  
   System.out.println(context.getName());  
   System.out.println(Arrays.toString(groups));  
     
   for (String grp: groups) {  
    if (grp.equalsIgnoreCase("smoke-test")) {  
     numTimes = 2;  
     break;  
    }  
   }  
   
   result = new Object[numTimes][];  
   for(int i=0;i<numTimes;i++) {  
    result[i] = new Object[] {new Integer(100 + i)};  
   }  
   return result;  
  }  
    
  @Test(dataProvider = "dpContext", groups = {"smoke-test"})  
  public void smokeTesting(int num) {  
   System.out.println("Data provided: " + num);  
  }  
    
  @Test(dataProvider = "dpContext", groups = {"regress-test"})  
  public void regressTesting(int num) {  
   System.out.println("Data provided: " + num);  
  }  
   
 }  

Below is the testng.xml:
 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >  
 <suite name="test-Dataprovider" verbose="1">  
  <test name="example-DP">  
   <groups>  
     <run>  
       <include name="smoke-test" />  
     </run>  
   </groups>  
   <classes>  
     <class  
     name="com.testng.test.DataProviderITestContext" />  
   </classes>  
  </test>  
 </suite>  

Below is the output:
[TestNG] Running:
  D:\eclipse_workspace\TestngWDFramework\testng.xml

example-DP
[smoke-test]
Data provided: 100
Data provided: 101

===============================================
test-Dataprovider
Total tests run: 2, Failures: 0, Skips: 0
===============================================

5) Lazy Data Provider using Iterator: A DataProvider method returns an Iterator instead of an array of arrays of objects. Whenever TestNg require the next set of parameters, it can instantiate the parameter and return it to the test method.
We will see the example in another post.
Read More »