tag:blogger.com,1999:blog-4584627466991560352024-03-13T21:28:22.242-07:00Terminal VelocityRandom musings about QA, Linux and Software TestingTerminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.comBlogger7125tag:blogger.com,1999:blog-458462746699156035.post-21363539002386624612013-12-29T18:08:00.001-08:002019-09-03T13:15:28.863-07:00Reducing complexity in Java using Groovy closuresWhile coding, do you ever get that feeling deep in your gut that the code you've just saved is <i>good enough</i> to get the job done, <b>but </b>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.<br />
<br />
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).<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-M6N8oMOKugw/UsDHzgds7lI/AAAAAAAACfo/bTz4iMjW7YE/s1600/Filters.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="101" src="https://4.bp.blogspot.com/-M6N8oMOKugw/UsDHzgds7lI/AAAAAAAACfo/bTz4iMjW7YE/s1600/Filters.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Figure 1. Example of web page displaying the filters</td></tr>
</tbody></table>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
So, to handle this I came up with a number of methods that looked like</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">filterByTitle(enteredValue);
filterByStatus(enteredValue);
<b>filterByReleaseDateOnFilm(enteredValue);</b>
</code></pre>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
These methods send the <span style="font-family: "courier new" , "courier" , monospace;">enteredValue </span>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 <b>Films </b>web page. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
However, another web page, labelled the <b>Releases </b>page, also displayed a<b> release date </b>filter. This resulted in another release date filter method -- one specific to the Releases page.<br />
<pre style="-webkit-text-stroke-width: 0px; background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; font-style: normal; font-variant: normal; letter-spacing: normal; line-height: 19px; margin: 15px 0px; orphans: auto; overflow: auto; padding: 6px 10px; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;"><b>filterByReleaseDateOnRelease(enteredValue);</b></code></pre>
</div>
<div style="text-align: left;">
As you can see, in order to differentiate between the two methods, I added an <i>OnFilm </i>and <i>OnRelease </i>suffix to each method, thereby identifying which web page each filter was associated with. This solution was <i>good enough </i>to test the filters on each web page, however, it just did not feel right. <br />
<br />
So, I started toying around with the idea of improving the code by implementing the functionality in Groovy. But how? Each of the <i>filter </i>methods resembled the following Java code. How could I improve on this kind of code?<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">private void filterByTitle(String enteredValue) {
filmsPage.sendTitle(enteredValue);
}
private void filterByStatus(String enteredValue) {
filmsPage.sendStatus(enteredValue);
}</code></pre>
Enter Groovy <a href="https://groovy-lang.org/closures.html" target="_blank">closures</a>! <br />
<br />
First, I identified what was common to each of the existing methods -- the <span style="font-family: "courier new" , "courier" , monospace;">enteredValue </span>parameter. Then, I asked myself what varied between each method -- it was the implementation (e.g., <span style="font-family: "courier new" , "courier" , monospace;">filmsPage.sendTitle(enteredValue)</span>). With this in mind I created the following method<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">void filterBy(String enteredValue, Closure closure) {
closure.call(enteredValue)
}</code></pre>
</div>
<br />
This method takes 2 parameters -- the <span style="font-family: "courier new" , "courier" , monospace;">enteredValue </span>and a <span style="font-family: "courier new" , "courier" , monospace;">closure</span>. The implementation of this method is designed to call the closure, passing it the <span style="font-family: "courier new" , "courier" , monospace;">enteredValue </span>parameter. Once, I had this in place, I replaced the existing methods with something like<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">filterBy(enteredValue) { value ->
filmsPage.sendTitle(value)
}
filterBy(enteredValue) { value ->
filmsPage.sendStatus(value)
}</code></pre>
The end result leads to less verbosity (in the way each method is named) and more maintainable code.Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com0tag:blogger.com,1999:blog-458462746699156035.post-78761319270816948012013-11-26T11:04:00.000-08:002013-11-26T11:04:50.297-08:00How about some grapes with that Groovy scriptRecently, 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. <br />
<br />
After some googling, I came across the <a href="https://github.com/xlson/groovycsv/">groovycsv</a> library. The groovycsv library relies on <a href="http://opencsv.sourceforge.net/">OpenCSV</a> and makes reading and writing to/from CSV files easy. Don't believe me, well, check out this example from the groovycsv site:<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">def csv = '''Name,Lastname
Mark,Andersson
Pete,Hansen'''
def data = parseCsv(csv)
for(line in data) {
println "$line.Name $line.Lastname"
}</code></pre>
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.<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">@Grab('com.xlson.groovycsv:groovycsv:1.0')
import static com.xlson.groovycsv.CsvParser.parseCsv</code></pre>
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 ( : ).<br />
<br />
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?<br />
<br />
Are you hungry for grapes? Grape stands for <b>Gr</b>oovy's <b>A</b>dvanced <b>P</b>ackage <b>E</b>ngine. It's the mechanism that provides a Groovy script with the capability to <i>grab </i>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:<br />
<br />
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background-color: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin: 0px; padding: 0px; word-wrap: normal;">@Grapes(
[@Grab('net.sf.opencsv:opencsv:2.3')
, @Grab('com.xlson.groovycsv:groovycsv:1.0')]
)
import static com.xlson.groovycsv.CsvParser.parseCsv</code></pre>
<br />
That's it! The next time the script is run, each of the noted dependencies will be <i>grabbed </i>from Maven and placed within <span style="font-family: Courier New, Courier, monospace;">~/.groovy/grapes</span>. 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.Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com0tag:blogger.com,1999:blog-458462746699156035.post-13822809620636477002011-04-07T15:40:00.000-07:002011-04-07T15:59:42.683-07:00Spring has arrivied -- working with Spring's JDBC TemplateSpring. 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 <a href="http://en.wikipedia.org/wiki/Spring_Framework">application framework</a> 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. <br />
<br />
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.<br />
<blockquote><span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 13px;">The Spring Framework takes care of all the grungy, low-level details that can make JDBC such a tedious API to develop with<sup><a href="http://terminalvelocity-socal.blogspot.com/2011/04/spring-has-arrivied-working-with.html#ref">1</a></sup>.</span></blockquote><blockquote><span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 13px;">The Spring JDBC template allows to clean-up the resources automatically, e.g. release the database connections.<br />
<br />
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 messages<sup><a href="http://terminalvelocity-socal.blogspot.com/2011/04/spring-has-arrivied-working-with.html#ref">2</a></sup>.<br />
</span></blockquote>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.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Setup</span><br />
I've set things up using Maven. The following represents the necessary dependencies required for this project.<br />
<br />
<br />
<dependencies><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><dependency><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><groupId>org.springframework</groupId><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><artifactId>spring-jdbc</artifactId><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><version>3.0.5.RELEASE</version><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span></dependency><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><dependency><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><groupId>mysql</groupId><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><artifactId>mysql-connector-java</artifactId><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><version>5.1.15</version><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span></dependency><br />
</dependencies><br />
<br />
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.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Implementation</span><br />
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.<br />
<br />
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.<br />
<br />
<u><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;">The Interface</span></u><br />
<br />
<code><br />
public interface IAccountDAO {<br />
<span class="Apple-tab-span" style="white-space: pre;"> </span>public String selectAccountNameById(int id);<br />
}<br />
</code><br />
We are going to extract the account's name from the database, using the specified identifier.<br />
<div><code><code><br />
</code></code></div><div><code><code><u><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;">The Class that Implements the Interface</span></u></code></code></div><div><code><code><u><br />
</u></code></code></div><div><div><code><code>import javax.sql.DataSource;</code></code></div><div><code><code>import org.springframework.jdbc.core.JdbcTemplate;</code></code></div><div><code><code><br />
</code></code></div><div><code><code>public class AccountJdbcTemplateDAOImpl implements IAccountDAO {</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>private JdbcTemplate jdbcTemplate;</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span></code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>public void setDataSource(DataSource dataSource) {</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>this.jdbcTemplate = new JdbcTemplate(dataSource);</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>}</code></code></div><div><code><code><br />
</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>public String selectAccountNameById(int id) {</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>// the SQL to execute</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>String sql = "SELECT account_name FROM accounts WHERE account_id = ?";</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>// using JDBC template, extract the account name</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>String accountName = (String)jdbcTemplate.queryForObject(sql, new Object[]{new Integer(id)}, String.class);</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span></code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>return accountName;</code></code></div><div><code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>}</code></code></div><div><code><code><br />
</code></code></div><div><code><code>}</code></code><br />
<code><code><br />
</code></code><br />
<span class="Apple-style-span" style="font-family: monospace;"><br />
</span><br />
Implementing the interfaces method, results in extracting the information we are after by using an SQL statement that is sent to JDBC's <b>queryForObject</b> method.<br />
<br />
<code><code><u><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;">The Main Class</span></u></code></code><br />
<code><code><u><br />
</u></code></code><br />
<code><code></code></code><br />
<code><code>import com.my.dao.AccountJdbcTemplateDAOImpl;</code></code><br />
<code><code>import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;</code></code><br />
<code><code><br />
</code></code><br />
<code><code>public class ConnectUsingJdbcTemplate {</code></code><br />
<code><code><br />
</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>/**</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span> * @param args</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span> */</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>public static void main(String[] args) {</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>AccountJdbcTemplateDAOImpl accountDAO = new AccountJdbcTemplateDAOImpl();</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>// create a MySQL data source</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>MysqlDataSource dataSource = new MysqlDataSource();</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>// assign properties to the data source </code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>dataSource.setUser("myuser");</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>dataSource.setPassword("mypassword");</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>dataSource.setURL("jdbc:mysql://localhost/mydb");</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span></code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>// assign the data source to the DAO object</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>accountDAO.setDataSource(dataSource);</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span></code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>// grab the account name and print it out to the console</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>System.out.println("Account Name = " + accountDAO.selectAccountNameById(1008));</code></code><br />
<code><code><span class="Apple-tab-span" style="white-space: pre;"> </span>}</code></code><br />
<code><code><br />
</code></code><br />
<code><code>}</code></code></div></div><div><code><code><br />
</code></code></div><div><code><code><br />
</code></code><br />
<br />
<a href="http://terminalvelocity-socal.blogspot.com/2011/04/spring-has-arrivied-working-with.html" name="ref">References</a><br />
1.<a href="http://static.springsource.org/spring/docs/2.0.8/reference/jdbc.html">http://static.springsource.org/spring/docs/2.0.8/reference/jdbc.html</a><br />
2.<a href="http://www.vogella.de/articles/SpringJDBC/article.html">http://www.vogella.de/articles/SpringJDBC/article.html</a><br />
</div>Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com0tag:blogger.com,1999:blog-458462746699156035.post-32594971505057798082011-01-06T07:45:00.000-08:002011-01-06T07:45:49.482-08:00Prey - An anti-theft application for your PC and Droid PhoneI recently came across an article that discusses <a href="http://www.unixmen.com/linux-tutorials/1418-prey-an-awesome-application-to-track-your-stolen-laptop-and-android-phone-li">Prey</a>. Prey is an anti-theft application designed to support your PC and Droid phones. You can read more about it here: <a href="http://www.unixmen.com/linux-tutorials/1418-prey-an-awesome-application-to-track-your-stolen-laptop-and-android-phone-li">http://www.unixmen.com/linux-tutorials/1418-prey-an-awesome-application-to-track-your-stolen-laptop-and-android-phone-li</a>Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com0tag:blogger.com,1999:blog-458462746699156035.post-68751171770571386852010-12-29T14:35:00.000-08:002010-12-29T14:35:28.709-08:00Ext4 filesystem hits Android, no need to fear data loss<a href="http://linuxtoday.com/news_story.php3?ltsn=2010-12-29-022-35-OS-MO">Ext4 filesystem hits Android, no need to fear data loss</a>: "<b>ars Technica:</b> 'Google's new Nexus S smartphone is the first Android device to use the Ext4 filesystem'"Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com0tag:blogger.com,1999:blog-458462746699156035.post-87729447951943704742010-11-29T08:35:00.000-08:002010-11-29T10:05:58.608-08:00Cucumber + Cuke4Duke + Selenium (WebDriver) = EnlightenmentThe 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 <a href="http://fitnesse.org/">FitNesse</a> and <a href="http://seleniumhq.org/">Selenium</a> (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 <i>very</i> successful for us.<br />
<br />
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:<br />
<ul><li><a href="http://www.easyb.org/">easyb</a></li>
<li><a href="http://code.google.com/p/givwenzen/">givwenzen</a></li>
<li><a href="http://cukes.info/">cucumber</a></li>
</ul>For reasons I won't delve into here, we opted for Cucumber. Specifically, we opted for the Cucumber + <a href="https://github.com/aslakhellesoy/cuke4duke/wiki">Cuke4Duke</a> + 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. <br />
<br />
Further research led me to several articles that helped me piece the puzzle together<sup><a href="http://terminalvelocity-socal.blogspot.com/2010/11/cucumber-cuke4duke-selenium-webdriver.html#refs">1</a></sup>. Once I had our project "mavenized" (a term I often use to indicate a project has been built with <a href="http://maven.apache.org/">Maven</a>), per the information contained in reference 1, I went on to install the necessary gems using the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">mvn -Dcucumber.installGems=true cuke4duke:cucumber</span> 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.<br />
<br />
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 <i>ease</i> 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.<br />
<br />
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<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>Ingredients</b></span><br />
Maven 2.2.x - 1 prerequisite<br />
<br />
Cucumber - 1 serving<br />
Cuke4Duke - 1 serving<br />
Selenium 2.0 - 1 serving (as of this writing, Selenium 2 is in its alpha phase)<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>Instructions</b></span><br />
<ol><li>Create a Maven project - we are currently using Eclipse to handle this. Essentially, create a project that contains the POM file outlined in <a href="https://github.com/aslakhellesoy/cuke4duke/wiki/maven">reference 1</a>.</li>
<li>Add the following to the POM file's dependencies node in order to provide for Selenium support<br />
<br />
<pre style="white-space: pre-wrap; word-wrap: break-word;"><dependencies></pre><span class="Apple-style-span" style="font-family: monospace;"><span class="Apple-style-span" style="font-family: 'Times New Roman';"><pre style="white-space: pre-wrap; word-wrap: break-word;"><dependency>
<blockquote class="webkit-indent-blockquote" style="border: none; margin: 0 0 0 40px; padding: 0px;"><groupId>org.seleniumhq.selenium</groupId>
</blockquote><blockquote class="webkit-indent-blockquote" style="border: none; margin: 0 0 0 40px; padding: 0px;"><artifactId>selenium</artifactId>
</blockquote><blockquote class="webkit-indent-blockquote" style="border: none; margin: 0 0 0 40px; padding: 0px;"><version>2.0a6</version>
</blockquote></dependency></pre><pre style="white-space: pre-wrap; word-wrap: break-word;"><span class="Apple-style-span" style="font-family: 'Times New Roman'; white-space: normal;"><pre style="white-space: pre-wrap; word-wrap: break-word;"></dependencies></pre><pre style="white-space: pre-wrap; word-wrap: break-word;"></pre><pre style="white-space: pre-wrap; word-wrap: break-word;"></pre></span></pre></span></span>and add the following to the POM file's repositories node<br />
<br />
<pre style="white-space: pre-wrap; word-wrap: break-word;"><repositories></pre><pre style="white-space: pre-wrap; word-wrap: break-word;"><span class="Apple-style-span" style="font-family: 'Times New Roman'; white-space: normal;"><pre style="white-space: pre-wrap; word-wrap: break-word;"><repository>
<blockquote class="webkit-indent-blockquote" style="border: none; margin: 0 0 0 40px; padding: 0px;"><id>selenium-repository</id> <url>http://selenium.googlecode.com/svn/repository/</url></blockquote></repository></pre></span></pre><pre style="white-space: pre-wrap; word-wrap: break-word;"><span class="Apple-style-span" style="font-family: 'Times New Roman'; white-space: normal;"><pre style="white-space: pre-wrap; word-wrap: break-word;"></repositories></pre><pre style="white-space: pre-wrap; word-wrap: break-word;"></pre></span></pre><br />
and add the following to the POM file's cucumberArgs node<br />
<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> <cucumberArgs></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> <cucumberArg>--require </span><span class="Apple-style-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">${basedir}/</span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">target/test-classes</cucumberArg></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </cucumberArgs></span><br />
<br />
<br />
</li>
<li>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.</li>
<li>Execute the following from the command line within the project's root directory (i.e., the POM file's location): <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">mvn -Dcucumber.installGems=true cuke4duke:cucumber</span>. This should install all the remaining dependencies, including the required gems needed to run Cucumber.</li>
<li>Create a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">features</span> directory under the project's root directory</li>
<li>Execute the following command from the project's directory to test out your installation: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">mvn cuke4duke:cucumber -DcukeArgs="--help"</span>. If all went well, you should see Cucumber's help message.</li>
</ol>That should be about it. Your project should be <i>fully baked</i>. Now, to actually begin using Cucumber, you'll need to create a feature file within the <i>features</i> directory created in step 5 above. I'll use the WebDriver <a href="http://code.google.com/p/selenium/wiki/GettingStarted">example</a> to illustrate this. Let's create the features file first. Label the file <i>search_for_cheese.feature </i><span class="Apple-style-span" style="font-family: inherit;">and save it to the features directory.</span><br />
<div><br />
</div><div>Feature: For the love of cheese</div><div>In order to find information about cheese</div><div>As a cheese lover</div><div>I want the ability to search Google for anything related to cheese</div><div><br />
</div><div>Scenario: The search for cheese</div><div>Given I have accessed Google's home page</div><div>When I enter the keyword of "Cheese"</div><div>And click the Submit button</div><div>Then the page title returned should be "Cheese - Google Search"</div><div><br />
</div><div>Now, let's create the class file containing the necessary Selenium code - label it <i>CheeseSteps.java </i>and save it to src/test/java.<br />
<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import org.openqa.selenium.By;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import org.openqa.selenium.WebDriver;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import org.openqa.selenium.WebElement;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import org.openqa.selenium.htmlunit.HtmlUnitDriver;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import cuke4duke.annotation.I18n.EN.Given;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import cuke4duke.annotation.I18n.EN.Then;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import cuke4duke.annotation.I18n.EN.When;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import static junit.framework.Assert.assertEquals;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class CheeseSteps {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">private WebDriver driver;</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">private WebElement element;</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public CheeseSteps() {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // Create a new instance of the html unit driver</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // Notice that the remainder of the code relies on the interface, </span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // not the implementation.</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> this.driver = new HtmlUnitDriver();</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">@Given("^I have accessed Google's home page$")</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public void iHaveAccessedGooglesHomePage() {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // And now use this to visit Google</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> driver.get("http://www.google.com");</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">@When("^I enter the keyword of \"(.*)\"$")</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public void iEnterTheKeyword(String keyword) {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // Find the text input element by its name</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> element = driver.findElement(By.name("q"));</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // Enter something to search for</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> element.sendKeys(keyword);</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">@When("^click the Submit button$")</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public void clickTheSubmitButton() {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> // Now submit the form. WebDriver will find the form for us from the element</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> element.submit();</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br />
</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">@Then("^the page title returned should be \"(.*)\"$")</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public void thePageTitleReturned(String expectedResults) {</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> assertEquals(expectedResults, driver.getTitle());</span><br />
<span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> </span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span><br />
<br />
<br />
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: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">mvn clean integration-test</span></div><div><br />
</div><div><br />
<a href="http://www.blogger.com/post-edit.g?blogID=458462746699156035&postID=8772944795194370474" name="refs">References</a><br />
1. <a href="https://github.com/aslakhellesoy/cuke4duke/wiki/Maven">Cuke4Duke Maven plugins</a><br />
2. <a href="http://cuke4ninja.com/toc.html">The Secret Ninja Cucumber Scrolls</a></div>Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com8tag:blogger.com,1999:blog-458462746699156035.post-24322226752122128442010-11-28T12:09:00.000-08:002010-11-28T12:09:27.129-08:00XargsXargs -- 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 <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">find</span> have trouble dealing with. As noted in <a href="http://en.wikipedia.org/wiki/Xargs">Wikipedia</a>,<br />
<br />
<span class="Apple-style-span" style="font-family: sans-serif; font-size: 13px; line-height: 19px;"></span><br />
<div class="mw-geshi" dir="ltr" style="background-color: #f9f9f9; border-bottom-color: rgb(47, 111, 171); border-bottom-style: dashed; border-bottom-width: 1px; border-left-color: rgb(47, 111, 171); border-left-style: dashed; border-left-width: 1px; border-right-color: rgb(47, 111, 171); border-right-style: dashed; border-right-width: 1px; border-top-color: rgb(47, 111, 171); border-top-style: dashed; border-top-width: 1px; color: black; line-height: 1.1em; padding-bottom: 1em; padding-left: 1em; padding-right: 1em; padding-top: 1em; text-align: left;"><div class="bash source-bash" style="font-family: monospace; line-height: normal;"><pre class="de1" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: white; border-bottom-style: none; border-bottom-width: 0px; border-left-color: white; border-left-style: none; border-left-width: 0px; border-right-color: white; border-right-style: none; border-right-width: 0px; border-top-color: white; border-top-style: none; border-top-width: 0px; color: black; font-family: monospace, 'Courier New' !important; font: normal normal normal 1em/1.2em monospace; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; vertical-align: top;"><span class="kw2" style="color: #c20cb9; font-weight: bold;">rm</span> <span class="sy0" style="color: black; font-weight: bold;">/</span>path<span class="sy0" style="color: black; font-weight: bold;">/*</span>
</pre></div></div><div style="line-height: 1.5em; margin-bottom: 0.5em; margin-left: 0px; margin-right: 0px; margin-top: 0.4em;">or</div><div class="mw-geshi" dir="ltr" style="background-color: #f9f9f9; border-bottom-color: rgb(47, 111, 171); border-bottom-style: dashed; border-bottom-width: 1px; border-left-color: rgb(47, 111, 171); border-left-style: dashed; border-left-width: 1px; border-right-color: rgb(47, 111, 171); border-right-style: dashed; border-right-width: 1px; border-top-color: rgb(47, 111, 171); border-top-style: dashed; border-top-width: 1px; color: black; line-height: 1.1em; padding-bottom: 1em; padding-left: 1em; padding-right: 1em; padding-top: 1em; text-align: left;"><div class="bash source-bash" style="font-family: monospace; line-height: normal;"><pre class="de1" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: white; border-bottom-style: none; border-bottom-width: 0px; border-left-color: white; border-left-style: none; border-left-width: 0px; border-right-color: white; border-right-style: none; border-right-width: 0px; border-top-color: white; border-top-style: none; border-top-width: 0px; color: black; font-family: monospace, 'Courier New' !important; font: normal normal normal 1em/1.2em monospace; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; vertical-align: top;"><span class="kw2" style="color: #c20cb9; font-weight: bold;">rm</span> <span class="sy0" style="color: black; font-weight: bold;">`</span><span class="kw2" style="color: #c20cb9; font-weight: bold;">find</span> <span class="sy0" style="color: black; font-weight: bold;">/</span>path <span class="re5" style="color: #660033;">-type</span> f<span class="sy0" style="color: black; font-weight: bold;">`</span>
</pre></div></div><div style="line-height: 1.5em; margin-bottom: 0.5em; margin-left: 0px; margin-right: 0px; margin-top: 0.4em;">will fail with an error message of "Argument list too long" if there are too many files in <code style="background-color: #f9f9f9; font-family: monospace, 'Courier New';">/path</code>. However this version (functionally equivalent to <code style="background-color: #f9f9f9; font-family: monospace, 'Courier New';">rm `find /path -type f`</code>) will not fail:</div><div class="mw-geshi" dir="ltr" style="background-color: #f9f9f9; border-bottom-color: rgb(47, 111, 171); border-bottom-style: dashed; border-bottom-width: 1px; border-left-color: rgb(47, 111, 171); border-left-style: dashed; border-left-width: 1px; border-right-color: rgb(47, 111, 171); border-right-style: dashed; border-right-width: 1px; border-top-color: rgb(47, 111, 171); border-top-style: dashed; border-top-width: 1px; color: black; line-height: 1.1em; padding-bottom: 1em; padding-left: 1em; padding-right: 1em; padding-top: 1em; text-align: left;"><div class="bash source-bash" style="font-family: monospace; line-height: normal;"><pre class="de1" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: white; border-bottom-style: none; border-bottom-width: 0px; border-left-color: white; border-left-style: none; border-left-width: 0px; border-right-color: white; border-right-style: none; border-right-width: 0px; border-top-color: white; border-top-style: none; border-top-width: 0px; color: black; font-family: monospace, 'Courier New' !important; font: normal normal normal 1em/1.2em monospace; line-height: normal; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; vertical-align: top;"><span class="kw2" style="color: #c20cb9; font-weight: bold;">find</span> <span class="sy0" style="color: black; font-weight: bold;">/</span>path <span class="re5" style="color: #660033;">-type</span> f <span class="re5" style="color: #660033;">-print0</span> <span class="sy0" style="color: black; font-weight: bold;">|</span> <span class="kw2" style="color: #c20cb9; font-weight: bold;">xargs</span> <span class="re5" style="color: #660033;">-0</span> <span class="kw2" style="color: #c20cb9; font-weight: bold;">rm</span></pre></div></div><br />
I have recently used it to process a list of files, changing the permission of each file to be read-write for the user.<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ls /home/user/*.txt | xargs chmod 600</span><br />
<br />
I have also used it in conjunction with <a href="http://cukes.info/">Cucumber</a>. 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 <a href="http://relishapp.com/">Relish</a> and <a href="https://github.com/burtlo/Cucumber-In-The-Yard">Cucumber-In-The-Yard</a>), but for now, I leveraged xargs.<br />
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">find features/ -name *.feature -type f -print0 | xargs -0 cat > features_and_scenarios.txt</span><br />
<div></div><br />
This finds all files that end with <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">.feature</span> and prints the results to standard output. It then takes the output and pipes it into the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">xargs</span> command, which runs it through the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">cat</span> command and finally writes the output of the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">cat</span> command to the <i>features_and_scenarios.txt</i> file.<br />
<br />
For more information on the xargs command, have a look at the <a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?xargs">man page</a>.Terminal Velocityhttp://www.blogger.com/profile/14657518389367199539noreply@blogger.com2