Danger, Danger!
Yet another programmer diary....
Saturday, 12 February 2011
Tuesday, 21 September 2010
Slides from Skillsmatter talk
I did a talk at Skillsmatter with Gojko last night. We discussed dividing UI testing into three levels (expanding on Gojko's post with examples), in order to increase maintainability of the tests.
I have embedded the slides from the talk below.
The code associated with these slides can be downloaded from cuke4ninja.com. Unpack the zip, the project is in the java/WebNinja directory.
There was quite a bit of discussion after the talk. Most centered around the usefulness of implementing cucumber features after development. The general feeling seemed to be that this was not an ideal situation, since one of the primary benefits of using cucumber is the collaboration it enables between all members of the team.
There were also questions regarding where responsibility lay for different parts of the code. Should the developers write all the code, should the test team have some input? My view is, that like many team organisation issues, it depends on the people involved. Maybe you have testers who would relish doing some ruby code!
I was also asked to show cucumber giving pdf output. This didn't work at the time, because I hadn't installed the prawn gem, and since the pub beckoned I said I would post instructions later. Anyway, you need to install the prawn gem to get the pdf output, like so...
.. or if you are using maven
You will also need to use the
Then when you run the tests use the -f[ormat] option to output to pdf, and specify the pdf file name.
These arguments can be configured in the pom file if you are using maven.
Thanks again to everyone who attended and to Skillsmatter for hosting the talk
I have embedded the slides from the talk below.
The code associated with these slides can be downloaded from cuke4ninja.com. Unpack the zip, the project is in the java/WebNinja directory.
There was quite a bit of discussion after the talk. Most centered around the usefulness of implementing cucumber features after development. The general feeling seemed to be that this was not an ideal situation, since one of the primary benefits of using cucumber is the collaboration it enables between all members of the team.
There were also questions regarding where responsibility lay for different parts of the code. Should the developers write all the code, should the test team have some input? My view is, that like many team organisation issues, it depends on the people involved. Maybe you have testers who would relish doing some ruby code!
I was also asked to show cucumber giving pdf output. This didn't work at the time, because I hadn't installed the prawn gem, and since the pub beckoned I said I would post instructions later. Anyway, you need to install the prawn gem to get the pdf output, like so...
gem install prawn
.. or if you are using maven
<gems>
...
<gem>install prawn</gem
</gems>
You will also need to use the
-Dcucumber.installGems=truecommand line parameter the first time you run with maven.
Then when you run the tests use the -f[ormat] option to output to pdf, and specify the pdf file name.
--format pdf --out target/cucumber/result.pdf
These arguments can be configured in the pom file if you are using maven.
Thanks again to everyone who attended and to Skillsmatter for hosting the talk
Monday, 20 September 2010
Cuke4Ninja
I've been working with Gojko Adzic on a e-Book aimed at encouraging the use of Cucumber.
I'm pleased (and relieved) to say that version 1 of the book is now released. You can read the book online or download a pdf copy at cuke4ninja.com.
The initial seed for the book came from a series of articles posted on Gojko's Blog which gave an easy to follow tutorial on how to setup Cucumber for use with .NET projects. Though Cucumber is very well documented, it's broad support of many programming languages means that the documentation is distributed across many sites. We thought that a single document that detailed using Cucumber from first principles would be useful and help grow the Cucumber user base.
Our concern that the book may be too dry, coupled with an obsession with Ninjas and Chuck Norris jokes, resulted in our decision to give the book a Ninja theme, hence the title "The Secret Ninja Cucumber Scrolls".
This first version covers Cucumber from the ground up, including:
We are following an iterative release schedule. In the next release, we will be covering Cucumber web automation. This subject is also the topic for a talk I'm doing with Gojko at Skillsmatter tonight. I'll publish the slides from that talk tomorrow.
To download the PDF or read the e-Book online, point your browser to cuke4ninja.com. For news and updates, follow cuke4ninja.
I'm pleased (and relieved) to say that version 1 of the book is now released. You can read the book online or download a pdf copy at cuke4ninja.com.
The initial seed for the book came from a series of articles posted on Gojko's Blog which gave an easy to follow tutorial on how to setup Cucumber for use with .NET projects. Though Cucumber is very well documented, it's broad support of many programming languages means that the documentation is distributed across many sites. We thought that a single document that detailed using Cucumber from first principles would be useful and help grow the Cucumber user base.
Our concern that the book may be too dry, coupled with an obsession with Ninjas and Chuck Norris jokes, resulted in our decision to give the book a Ninja theme, hence the title "The Secret Ninja Cucumber Scrolls".
This first version covers Cucumber from the ground up, including:
- Overview of Cucumber, including a glossary of Cucumber and BDD terminology
- Setting up Cucumber for Ruby, Java and .NET projects
- Implementing basic features in all three languages
- Effective test design
- Managing complex features efficiently.
We are following an iterative release schedule. In the next release, we will be covering Cucumber web automation. This subject is also the topic for a talk I'm doing with Gojko at Skillsmatter tonight. I'll publish the slides from that talk tomorrow.
To download the PDF or read the e-Book online, point your browser to cuke4ninja.com. For news and updates, follow cuke4ninja.
Wednesday, 18 August 2010
Logging in Objective-C with Blocks
I've been learning Objective-C in my spare time, focusing on coding for iOS devices in particular. I tend to use debugging as the last resort when writing code, so logging is important. I have found the lack of decent logging in iOS to be a problem.
Being used to logging on java and .Net, NSLog does seem very primitive, and one solution does appear to be cocoalumberjack. I will be investigating this and doing a post soon.
In the mean time I am experimenting with using blocks to give me the flexibility I need as a minimum. This was partly motivated as a learning exercise for closures in Objective-C
The basic Logger header looks like this:
.. so a simple logger API then. The interesting part as far as I am concerned is this bit...
There is a full discussion on block syntax here, so I am not going to go into lots of detail. The example above is defining a block which takes no parameters and returns a string.
Inside the implementation, the block is used like a normal C function
This means that any expensive operations inside the block are not called if the log level is not met. To use the logger, the code looks like this
Note how because the block is a closure, it can use other variables that are in scope.
Being used to logging on java and .Net, NSLog does seem very primitive, and one solution does appear to be cocoalumberjack. I will be investigating this and doing a post soon.
In the mean time I am experimenting with using blocks to give me the flexibility I need as a minimum. This was partly motivated as a learning exercise for closures in Objective-C
The basic Logger header looks like this:
typedef enum {
kError = 0,
kWarn,
kInfo,
kDebug,
} TRLLogLevel;
@interface TRLLog : NSObject
+(void)logWithBlock:(NSString* (^)(void))block withLevel:(TRLLogLevel)level;
+(void)setLogLevel:(TRLLogLevel)level;
+(void)error:(NSString* (^)(void))block;
+(void)warn:(NSString* (^)(void))block;
+(void)info:(NSString* (^)(void))block;
+(void)debug:(NSString* (^)(void))block;
@end
.. so a simple logger API then. The interesting part as far as I am concerned is this bit...
(NSString* (^)(void))
There is a full discussion on block syntax here, so I am not going to go into lots of detail. The example above is defining a block which takes no parameters and returns a string.
Inside the implementation, the block is used like a normal C function
+(void)logWithBlock:(NSString* (^)(void))block withLevel:(TRLLogLevel)level {
if (level > currentLogLevel)
return;
NSString *msg = block();
NSLog(@"%@",msg);
[msg release];
}
This means that any expensive operations inside the block are not called if the log level is not met. To use the logger, the code looks like this
CGPoint point = [recogniser translationInView:self.view];
[TRLLog debug:^{
return [[NSString alloc]initWithFormat:@"handlePan [%f, %f]",point.x,point.y];
}];
Note how because the block is a closure, it can use other variables that are in scope.
Wednesday, 8 April 2009
DBDeploy + Maven + MySQL
I wanted to have a way of controlling database updates for the project I am working on. I was aiming for the following:
1. A series of database deltas
2. A Database on each developer machine, and on each of the CI environments
3. The deltas to be applied in order and only once
4. Each database to have a list of applied deltas
5. I wanted the database versioning to be part of CI
These goals were fairly straightforward, and I did not see the need to write code to achieve this. At the suggestion of a colleague, I looked at DBDeploy.
This seemed to provide the features I wanted and is pretty trivial to set up, as described here. However there were a few complications, primarily due to Maven and MySQL.
1. DBDeploy has an Ant target, but no maven plugin. I therefore used the Maven Antrun plugin to call the DBDeploy Ant target
2. MySql has no differentiation between end of statement and end of block. This can be a problem when scripting procedures. The work-around is to use a different delimiter. In my delta scripts I use #.
Unfortunately (for me) however DBDeploy works by concatenating all deltas into one script and adding it's own versioning statements at either end. These statements are hard coded to use a semi-colon delimiter.
In order to be able to use a different delimiter, it was therefore necessary to do some post processing on the file. Since I was already using the Antrun plugin and ant has some good targets for this kind of thing, I used the Ant replace and replaceregex Ant targets to do this.
3. In order to run the script as part of CI, I used the sql-maven-plugin and changed the delimiter to #
The plugin configuration was as follows:
1. A series of database deltas
2. A Database on each developer machine, and on each of the CI environments
3. The deltas to be applied in order and only once
4. Each database to have a list of applied deltas
5. I wanted the database versioning to be part of CI
These goals were fairly straightforward, and I did not see the need to write code to achieve this. At the suggestion of a colleague, I looked at DBDeploy.
This seemed to provide the features I wanted and is pretty trivial to set up, as described here. However there were a few complications, primarily due to Maven and MySQL.
1. DBDeploy has an Ant target, but no maven plugin. I therefore used the Maven Antrun plugin to call the DBDeploy Ant target
2. MySql has no differentiation between end of statement and end of block. This can be a problem when scripting procedures. The work-around is to use a different delimiter. In my delta scripts I use #.
Unfortunately (for me) however DBDeploy works by concatenating all deltas into one script and adding it's own versioning statements at either end. These statements are hard coded to use a semi-colon delimiter.
In order to be able to use a different delimiter, it was therefore necessary to do some post processing on the file. Since I was already using the Antrun plugin and ant has some good targets for this kind of thing, I used the Ant replace and replaceregex Ant targets to do this.
3. In order to run the script as part of CI, I used the sql-maven-plugin and changed the delimiter to #
The plugin configuration was as follows:
...
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<configuration>
<tasks>
<taskdef name="dbdeploy" classname="net.sf.dbdeploy.AntTarget"/>
<taskdef name="ReplaceRegExp" classname="org.apache.tools.ant.taskdefs.optional.ReplaceRegExp"/>
<mkdir dir="${basedir}/target/db"/>
<dbdeploy
driver="com.mysql.jdbc.Driver"
url="${db.url}"
userid="${db.user}"
password="${db.password}"
dir="${basedir}/src/main/resources/db/deltas"
outputfile="${basedir}/target/db/all-deltas.sql"
dbms="mysql"
undoOutputfile="${basedir}/target/db/undo-all-deltas.sql"
/>
<replace dir="${basedir}/target/" token="COMMIT;" value="COMMIT#">
<include name="**/*.sql"/>
</replace>
<replaceregexp byline="true">
<regexp pattern=" changelog(.*);"/>
<substitution expression=" changelog\1#"/>
<fileset dir="${basedir}/target/">
<include name="**/*.sql"/>
</fileset>
</replaceregexp>
<replace dir="${basedir}/target/" token="@DBNAME@" value="${db.name}">
<include name="**/*.sql"/>
</replace>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>dbdeploy</groupId>
<artifactId>dbdeploy</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>1.7.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.1</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
<configuration>
<driver>com.mysql.jdbc.Driver</driver>
<autocommit>true</autocommit>
<delimiter>#</delimiter>
</configuration>
<executions>
<execution>
<id>update-schema-db</id>
<phase>generate-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<url>${db.url}</url>
<username>${db.user}</username>
<password>${db.password}</password>
<fileset>
<basedir>${basedir}/target/db</basedir>
<includes>
<include>all-deltas.sql</include>
</includes>
</fileset>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
Wednesday, 25 March 2009
Tuckey URL Rewriter
I have been using a url rewriting plugin for Spring, that allows urls to be less cluttered with querystring params. I am using it as an interim step before sorting a proper photo cache.
What I want is to have a url like:
Spring 3.0 will allow this kind of thing, but for the moment there is a url rewriting filter from http://tuckey.org
The steps I used were:
1. Add a dependency to the pom file
2. Add a filter to web.xml
3. Add a file called urlwrite.xml to WEB-INF
Where <from> and <to> are regular expression match and replace values
4. Create a normal Spring controller and configuration to handle requests like
This means that later I can cache the picture as a file and change the controller to being a 404 handler.
What I want is to have a url like:
/cache/player/1/picture
Spring 3.0 will allow this kind of thing, but for the moment there is a url rewriting filter from http://tuckey.org
The steps I used were:
1. Add a dependency to the pom file
<dependency>
<groupid>org.tuckey</groupid>
<artifactid>urlrewrite</artifactid>
<version>2.5.2</version>
</dependency>
2. Add a filter to web.xml
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
3. Add a file called urlwrite.xml to WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN" "http://tuckey.org/res/dtds/urlrewrite3.0.dtd">
<urlrewrite>
<rule>
<from>/cache/player/([0-9]+)/picture$</from>
<to>/cache/player/picture?accountId=$1</to>
</rule>
Where <from> and <to> are regular expression match and replace values
4. Create a normal Spring controller and configuration to handle requests like
/cache/player/picture?accountId=1
This means that later I can cache the picture as a file and change the controller to being a 404 handler.
Subscribe to:
Posts (Atom)