Sunday, December 29, 2013

Reducing complexity in Java using Groovy closures

While coding, do you ever get that feeling deep in your gut that the code you've just saved is good enough to get the job done, but you feel that it might have been over-engineered or probably is a bit too complex for the problem at hand.  That happened to me recently after saving some Java code I was using to test a web application.  I had just added another method (very similar to the half dozen other methods within the same class), when it occurred to me that if I continued down the path I had laid out for myself, the code could soon become too verbose.

Before delving into the code and the solution I came up with, there's a bit of context I'd like to share about the application under test.  The code in question revolves around filtering content displayed on certain web pages by entering a value.  The idea here, is to use Selenium to enter the specified value into the designated filter (Figure 1).

Figure 1. Example of web page displaying the filters

So, to handle this I came up with a number of methods that looked like
filterByTitle(enteredValue);
filterByStatus(enteredValue);
filterByReleaseDateOnFilm(enteredValue);

These methods send the enteredValue to the appropriate Selenium page object class for further processing -- i.e., sending the text value to the correct filter.  Each of the above methods were associated with the Films web page.  

However, another web page, labelled the Releases page, also displayed a release date filter.  This resulted in another release date filter method -- one specific to the Releases page.
filterByReleaseDateOnRelease(enteredValue);
As you can see, in order to differentiate between the two methods, I added an OnFilm and OnRelease suffix to each method, thereby identifying which web page each filter was associated with.  This solution was good enough to test the filters on each web page, however, it just did not feel right.

So, I started toying around with the idea of improving the code by implementing the functionality in Groovy. But how?  Each of the filter methods resembled the following Java code.  How could I improve on this kind of code?
private void filterByTitle(String enteredValue) {
        filmsPage.sendTitle(enteredValue);
}

private void filterByStatus(String enteredValue) {
        filmsPage.sendStatus(enteredValue);
}
Enter Groovy closures!

First, I identified what was common to each of the existing methods --  the enteredValue parameter.  Then, I asked myself what varied between each method -- it was the implementation (e.g., filmsPage.sendTitle(enteredValue)).  With this in mind I created the following method

void filterBy(String enteredValue, Closure closure) {
        closure.call(enteredValue)
}

This method takes 2 parameters -- the enteredValue and a closure.  The implementation of this method is designed to call the closure, passing it the enteredValue parameter.  Once, I had this in place, I replaced the existing methods with something like

filterBy(enteredValue) { value ->
 filmsPage.sendTitle(value)
}

filterBy(enteredValue) { value ->
 filmsPage.sendStatus(value)
}
The end result leads to less verbosity (in the way each method is named) and more maintainable code.

Tuesday, November 26, 2013

How about some grapes with that Groovy script

Recently, I created my first Groovy script. Mind you, I've been tinkering with Groovy for the past couple of weeks, but most of the stuff I've been doing has involved just a few lines of code. So, when it came time to create a program that reads in data from a CSV file and prints out each column and its associated value in a readable manner, I turned to Groovy.

After some googling, I came across the groovycsv library. The groovycsv library relies on OpenCSV and makes reading and writing to/from CSV files easy. Don't believe me, well, check out this example from the groovycsv site:
def csv = '''Name,Lastname
Mark,Andersson
Pete,Hansen'''

def data = parseCsv(csv)
for(line in data) {
    println "$line.Name $line.Lastname"
}
Yet, if I wanted to run this script "as is", it would fail to work because the groovycsv library is not a part of the class path or some such nonsense ;-).  Well, a closer look at the example provided by the groovycsv team suggests that the following 2 lines of code should be included with the script.
@Grab('com.xlson.groovycsv:groovycsv:1.0')
import static com.xlson.groovycsv.CsvParser.parseCsv
Wait ... what?!?!  What's this @Grab thing?  Well, after some further googling, it turns out that Groovy scripts support Maven dependencies.  These can be included using the @Grab annotation.  The syntax is quite similar to Maven's groupId, artifactId and version call outs -- the difference being each value is separated by a colon ( : ).

The first time the script is executed, the dependency is retrieved from Maven (at run-time) and then its made available to the script by supplying the correct import statement.  Kinda cool.  But, what if you've got a number of dependencies that are required?

Are you hungry for grapes?  Grape stands for Groovy's Advanced Package Engine.  It's the mechanism that provides a Groovy script with the capability to grab a Maven dependency.   With respect to the example code above, even after adding the groovycsv dependency, the script would fail due to a missing CSVReader class. The CSVReader class is code that is contained within the OpenCSV library.  Here's how to overcome this issue using Grape:

@Grapes(
        [@Grab('net.sf.opencsv:opencsv:2.3')
        , @Grab('com.xlson.groovycsv:groovycsv:1.0')]
)
import static com.xlson.groovycsv.CsvParser.parseCsv

That's it!  The next time the script is run, each of the noted dependencies will be grabbed from Maven and placed within ~/.groovy/grapes.  Now, all dependencies are satisfied.  Even better -- if you share this script with someone else or you run it on a different platform, Groovy should grab what you need.

Thursday, April 7, 2011

Spring has arrivied -- working with Spring's JDBC Template

Spring. It brings to mind rebirth; the season of regrowth, and new beginnings.  Rarely, if at all, when mentioned in non-technical circles, does the term "Spring" bring to mind an open source application framework for the Java platform.  But, that is exactly what does come to mind, if you happen to have a technical conversation amongst a number of Java developers.   Considering that I am not a Java developer (my day job involves being a member of a Quality Assurance team), I was interested to know what a Java developer might recommend when it came to communicating with a database.

I had dabbled with using JDBC in the past, and had some limited success with it, however, the fact that using a pure implementation of JDBC meant that I would need to manage the connection(s) as well as any errors that might arise, got me to thinking if there wasn't some sort of alternative. After a brief discussion with one of our developers, he informed me of something called JDBC Template.  JDBC Template is a part of the Spring Framework.  What's the point of using JDBC Template, if I can just use the JDBC API, you may ask? Well, I'll defer the answer to that question to a couple of online resources.
The Spring Framework takes care of all the grungy, low-level details that can make JDBC such a tedious API to develop with1.
The Spring JDBC template allows to clean-up the resources automatically, e.g. release the database connections.

The Spring JDBC template converts the standard JDBC SQLExceptions into RuntimeExceptions. This allows the programmer to react more flexible to the errors. The Spring JDBC template converts also the vendor specific error messages into better understandable error messages2.
Essentially, this results in easier to read/maintain code by removing the boiler-plate coding required to manage JDBC resources.  In order to test out this framework, let's delve into an example that I put together to help me understand the use and benefits of JDBC Template.  First off, we'll need to get things setup before moving forward -- this example uses MySQL as the database, and assumes some knowledge of Java and Maven.

Setup
I've set things up using Maven.  The following represents the necessary dependencies required for this project.


  <dependencies>
   <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>3.0.5.RELEASE</version>
   </dependency>
   <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.15</version>
   </dependency>
  </dependencies>

The first dependency pulls in the necessary Spring JDBC Framework.  The second dependency noted, pulls in the MySQL Java Connector required to communicate with the MySQL database.

Implementation
In order to extract and/or update information within the database, we will need to create an interface to the specified table.  The interface will then be implemented by a class that contains the necessary instance of the JdbcTemplate.  This is the convention normally taken when developing DAO artifacts.

The following code assumes that a local MySQL database exists with a table labeled Account that contains, for the purposes of this example, an account_name field and an account_id field.

The Interface


public interface IAccountDAO {
public String selectAccountNameById(int id);
}

We are going to extract the account's name from the database, using the specified identifier.

The Class that Implements the Interface

import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

public class AccountJdbcTemplateDAOImpl implements IAccountDAO {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public String selectAccountNameById(int id) {
// the SQL to execute
String sql = "SELECT account_name FROM accounts WHERE account_id = ?";
// using JDBC template, extract the account name
String accountName = (String)jdbcTemplate.queryForObject(sql, new Object[]{new Integer(id)}, String.class);
return accountName;
}

}




Implementing the interfaces method, results in extracting the information we are after by using an SQL statement that is sent to JDBC's queryForObject method.

The Main Class



import com.my.dao.AccountJdbcTemplateDAOImpl;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;


public class ConnectUsingJdbcTemplate {


/**
* @param args
*/
public static void main(String[] args) {
AccountJdbcTemplateDAOImpl accountDAO = new AccountJdbcTemplateDAOImpl();
// create a MySQL data source
MysqlDataSource dataSource = new MysqlDataSource();
// assign properties to the data source 
dataSource.setUser("myuser");
dataSource.setPassword("mypassword");
dataSource.setURL("jdbc:mysql://localhost/mydb");

// assign the data source to the DAO object
accountDAO.setDataSource(dataSource);

// grab the account name and print it out to the console
System.out.println("Account Name = " + accountDAO.selectAccountNameById(1008));
}


}

Thursday, January 6, 2011

Prey - An anti-theft application for your PC and Droid Phone

I recently came across an article that discusses Prey.  Prey is an anti-theft application designed to support your PC and Droid phones.  You can read more about it here: http://www.unixmen.com/linux-tutorials/1418-prey-an-awesome-application-to-track-your-stolen-laptop-and-android-phone-li

Wednesday, December 29, 2010

Ext4 filesystem hits Android, no need to fear data loss

Ext4 filesystem hits Android, no need to fear data loss: "ars Technica: 'Google's new Nexus S smartphone is the first Android device to use the Ext4 filesystem'"

Monday, November 29, 2010

Cucumber + Cuke4Duke + Selenium (WebDriver) = Enlightenment

The journey to a better understanding of Acceptance Test Driven Development (ATDD)/Behavior Driven Development (BDD) has been circuitous at best.  It's a journey that began for me over a year and a half ago.  During that time, I've plodded along, attempting to gain insight into what the community is using to solve the problem of how to effectively test web applications and how to produce test results that make sense to technical and non-technical users.  Our team (QA team), had been - and still is - focused on supporting a number of our web-based projects through the use of automated tests.  For the most part, these tests are supported using tools such as FitNesse and Selenium (either version 1.0.x or 2.0).  We also developed a test harness based on Selenium and JUnit, but that has not worked out too well for our non-technical users. In general, the combination of FitNesse and Selenium has proved to be very successful for us.

Several months back, however, I began wondering if there were other open source tools that could sustain our existing requirements, and in addition, provide a simpler solution for our non-technical users (business analysts, product managers, testers, and management).  My research led me to several solutions that, I felt, might work out:
For reasons I won't delve into here, we opted for Cucumber. Specifically, we opted for the Cucumber + Cuke4Duke + Selenium solution.  We went with Cuke4Duke primarily because our development team uses Java, and because we have several members of our team that are quite familiar with Java. Although the toolkit I opted for promised to help solve some of our issues, getting the various tools installed and configured proved to be much more of a challenge than I had expected - particularly, the Cuke4Duke component.

Further research led me to several articles that helped me piece the puzzle together1.  Once I had our project "mavenized" (a term I often use to indicate a project has been built with Maven), per the information contained in reference 1, I went on to install the necessary gems using the mvn -Dcucumber.installGems=true cuke4duke:cucumber command outlined in references 1 and 2.  Then, I set about meeting with our subject matter expert to collaborate on the various features and scenarios that would make up the initial sanity test. After putting together a handful of scenarios together, we implemented the Java code required to test our web application.

Although I have only worked with Cucumber for a short period of time, it's apparent to me that one of Cucumber's greatest strengths is the ease with which one can move from creating the features and scenarios, to building the step definitions, to implementing the underlying code that ties back to the application under test. And, since the features and scenarios are contained in simple text files, collaboration between technical and non-technical users is simplified - no need to learn a new tool, or familiarize yourself with a special markup language - the scenarios are plain text files that can be easily shared between team members using any editor.  Too doggone simple.  That is when the proverbial "light-bulb went off in my head". Suddenly, I felt enlightened and empowered at the same time.

So, with all that being said, here is a brief guide of what you will need to get Cucumber + Cuke4Duke + Selenium up and running.  The recipe goes something like this

Ingredients
Maven 2.2.x - 1 prerequisite

Cucumber - 1 serving
Cuke4Duke - 1 serving
Selenium 2.0 - 1 serving (as of this writing, Selenium 2 is in its alpha phase)

Instructions
  1. Create a Maven project - we are currently using Eclipse to handle this.  Essentially, create a project that contains the POM file outlined in reference 1.
  2. Add the following to the POM file's dependencies node in order to provide for Selenium support

    <dependencies>
    <dependency>
    
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium</artifactId>
    <version>2.0a6</version>
    </dependency>
    </dependencies>
    and add the following to the POM file's repositories node

    <repositories>
    <repository>
    
    <id>selenium-repository</id> <url>http://selenium.googlecode.com/svn/repository/</url>
    </repository>
    </repositories>

    and add the following to the POM file's cucumberArgs node


    <cucumberArgs>
      <cucumberArg>--require ${basedir}/target/test-classes</cucumberArg>
    </cucumberArgs>


  3. Save the POM file.  Saving the POM file should begin the process of downloading a number of Maven dependencies.  Wait until those dependencies are downloaded, before moving on to the next step.
  4. Execute the following from the command line within the project's root directory (i.e., the POM file's location): mvn -Dcucumber.installGems=true cuke4duke:cucumber.  This should install all the remaining dependencies, including the required gems needed to run Cucumber.
  5. Create a features directory under the project's root directory
  6. Execute the following command from the project's directory to test out your installation:  mvn cuke4duke:cucumber -DcukeArgs="--help".  If all went well, you should see Cucumber's help message.
That should be about it.  Your project should be fully baked. Now, to actually begin using Cucumber, you'll need to create a feature file within the features directory created in step 5 above. I'll use the WebDriver example to illustrate this.  Let's create the features file first. Label the file search_for_cheese.feature and save it to the features directory.

Feature: For the love of cheese
In order to find information about cheese
As a cheese lover
I want the ability to search Google for anything related to cheese

Scenario: The search for cheese
Given I have accessed Google's home page
When I enter the keyword of "Cheese"
And click the Submit button
Then the page title returned should be "Cheese - Google Search"

Now, let's create the class file containing the necessary Selenium code - label it CheeseSteps.java and save it to src/test/java.


import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import cuke4duke.annotation.I18n.EN.Given;
import cuke4duke.annotation.I18n.EN.Then;
import cuke4duke.annotation.I18n.EN.When;
import static junit.framework.Assert.assertEquals;


public class CheeseSteps  {
private WebDriver driver;
private WebElement element;


public CheeseSteps() {
 // Create a new instance of the html unit driver
 // Notice that the remainder of the code relies on the interface, 
 // not the implementation.
 this.driver = new HtmlUnitDriver();
}


@Given("^I have accessed Google's home page$")
public void iHaveAccessedGooglesHomePage() {
 // And now use this to visit Google
 driver.get("http://www.google.com");
}


@When("^I enter the keyword of \"(.*)\"$")
public void iEnterTheKeyword(String keyword) {
 // Find the text input element by its name
 element = driver.findElement(By.name("q"));
 // Enter something to search for
 element.sendKeys(keyword);
}


@When("^click the Submit button$")
public void clickTheSubmitButton() {
 // Now submit the form. WebDriver will find the form for us from the element
 element.submit();
}


@Then("^the page title returned should be \"(.*)\"$")
public void thePageTitleReturned(String expectedResults) {
 assertEquals(expectedResults, driver.getTitle());
}
}


Essentially, the above code wraps the WebDriver example within the noted Given/When/Then annotations supported by Cucumber.  To see the test in action, from within the project's directory execute the following command: mvn clean integration-test

Sunday, November 28, 2010

Xargs

Xargs -- a versatile UNIX command that allows you to build and execute command lines from standard input.  Think of it as a slightly more efficient way of processing lists of standard input that certain commands like find have trouble dealing with.  As noted in Wikipedia,


rm /path/*
or
rm `find /path -type f`
will fail with an error message of "Argument list too long" if there are too many files in /path. However this version (functionally equivalent to rm `find /path -type f`) will not fail:
find /path -type f -print0 | xargs -0 rm

I have recently used it to process a list of files, changing the permission of each file to be read-write for the user.

ls /home/user/*.txt | xargs chmod 600

I have also used it in conjunction with Cucumber.  In this particular scenario, I needed some way of producing a single text file that contained all of the features and scenarios, so that I could go over them with a team of developers, testers and business analysts.  At the moment, Cucumber does not support a way (or at least I have not found a method yet) of extracting all of the scenarios into one or more files.  There are some tools that are actively being developed that should alleviate this issue in the future (see Relish and Cucumber-In-The-Yard), but for now, I leveraged xargs.

find features/ -name *.feature -type f -print0 | xargs -0 cat > features_and_scenarios.txt

This finds all files that end with .feature and prints the results to standard output.  It then takes the output and pipes it into the xargs command, which runs it through the cat command and finally writes the output of the cat command to the features_and_scenarios.txt file.

For more information on the xargs command, have a look at the man page.