nosewheelie

Technology, mountain biking, politics & music.

Archive for July, 2008

Testing in Scala using a Java tool

without comments

My first post on Graceless Failures, a blog about adventures on the path to learning Scala:

Scala, like a lot of other languages these days, ships with a unit testing framework – SUnit – built in. Many other Scala specific “testing” frameworks have sprung up in recent times that contain similar or vastly different feature sets to the traditional xUnit tools. These include Reductio, ScalaCheck, Specs, ScalaTest, and SUnit (built into the Scala distribution).

And as Scala is “just Java” you can also use Java frameworks such as JUnit and TestNG. Having only used Reductio, I can’t vouch for any others, though ScalaTest is getting good airplay on Artima and Specs seems to have the Scala BDD mindshare.

These tools can be loosely categorised as traditional unit testing tools, ala xUnit, or automated specification testing tools, ala QuickCheck. Reductio and ScalaCheck are incarnations of automated specification testing, while Specs, ScalaTest and SUnit are more your traditional xUnit frameworks.

However, I’m not to write about any of these frameworks, instead, I’m going to write about Instinct, a Java BDD framework that I’ve been developing for around 18 months, and for which I’ve recently started to add specific support for Scala into the codebase. Good fodder for blog posts!

Continue reading Testing in Scala using a Java tool.

Written by Tom Adams

July 29th, 2008 at 9:43 am

Instinct 0.1.8 Release

without comments

I’m happy to announce the release of Instinct 0.1.8. This is a maintenance release resolving some minor bugs and packaging issues from the 0.1.7 release.

Chris has been spiking some Spring integration and needed a way to turn off detection of specs based on naming conventions and annotations so this is in this release also. Currently it’s only available via the @Context annotation, so you’ll have to annotate each class you want to override the default behaviour on. If there’s enough interest in this, I’ll add a way to change this globally.

Downloads are available from the project site.

Here’s the full list of changes:

  • Core Features
    • Custom specification, before specification and after specification annotations and naming conventions can be provided via the Context annotation. This can also be used to turn off naming convention-based detection (using NoNamingConvention).
  • Infrastructure
    • Upgraded to: Functional Java 2.8.
  • Bugs
    • (Issue 36) Abstract classes are being run as a result of specification runner refactoring.
    • (Issue 37) Expected exceptions are being printed to console in Ant runner even though spec passes.
    • (Issue 38) Functional java jar is not included in release zip.

Written by Tom Adams

July 26th, 2008 at 2:22 pm

Posted in BDD,Instinct,Java

Instinct 0.1.7 Release

without comments

I’m happy to announce the release of Instinct 0.1.7. This is mainly a maintenance release, and includes the removal of in progress specification state, runners now emit pending reason, added Functional Java based matchers, upgrades to dependencies, Ant 1.7.1, CGLib 2.2, jMock 2.5.0 and Objenesis 1.1 and an internal re-write of specification runners.

Note that the upgrade to jMock 2.5.0 may cause issues with current mocks, you should consult the jMock documentation and release notes if you run into trouble. I’ve also added a new dependency on Functional Java, which is used both internally and can be used from two new matchers.

Downloads are available from the project site.

Here’s the full list of changes:

  • Core Features
    • Removed in progress specification state, use pending instead.
    • All runners now emit pending specification reason.
  • Expectation API
    • Added function matcher, e.g. expect.that(list).doesNotContain({int i => i > 3} (based on Functional Java’s fj.F).
    • Added fj.data.List matcher.
  • Infrastructure
    • Added dependency on Functional Java, used both internally and for use in expectation API.
    • Continued clean up of specification running code.
    • Upgraded to: Ant 1.7.1, CGLib 2.2, jMock 2.5.0 and Objenesis 1.1.
  • Bugs
    • (Issue 11) It would be nice not to have to depend on jmock when writing a BDD-style test involving no mocks.

Written by Tom Adams

July 25th, 2008 at 8:30 am

Posted in BDD,Functional,Instinct

Tagged with

Nobody *ever* uses map, et. al… (example 3)

without comments

Continuing my nobody *ever* uses series, here’s a Java example.

Consider the following horrible piece of Java code taken from Instinct which finds specifications to run:

private Collection<LifecycleMethod> findMethods(final MarkingScheme markingScheme) {
    final Collection<LifecycleMethod> lifecycleMethodSet = new HashSet<LifecycleMethod>();
    final Collection<Method> methods = methodLocator.locateAll(contextType, markingScheme);
    for (final Method method : methods) {
        lifecycleMethodSet.add(new LifecycleMethodImpl(method, contextType));
    }
    return lifecycleMethodSet;
}

Here’s the same method rewritten using Functional Java, with the conversion function pulled out for clarity:

private Collection<LifecycleMethod> findMethods(final MarkingScheme markingScheme) {
    final F<Method, LifecycleMethod> conversion = new F<Method, LifecycleMethod>() {
        public LifecycleMethod f(final Method a) {
            return new LifecycleMethodImpl(a, contextType);
        }
    };
    final Collection<Method> methods = methodLocator.locateAll(contextType, markingScheme);
    return toFjList(methods).map(conversion).toCollection();
}

The good thing about the above is it expresses succinctly what we’re doing; find the methods we’re interested in and map across them to convert them into another type. The unfortunate things are that we have to convert from a Java collection to a FJ collection (toFjList) and we need to use the clunky Java anonymous inner class as a pseudo first class function.

For comparison, here’s a rough stab (i.e. probably won’t compile) at what it’d look like in Scala, notice that implicits will take care of the conversion for us:

def findMethods(markingScheme: MarkingScheme) =
  methodLocator.locateAll(contextType, markingScheme).map(new LifecycleMethodImpl(_, contextType))

Now isn’t that better?

Written by Tom Adams

July 21st, 2008 at 2:11 pm

iPhone sites launch

with 4 comments

Well it’s finally official, and public. After two solid months of development, today marks the launch of the three iPhone sites we’ve been working on:

Screenshots of the sites courtesy of Pete.

These sites may not work on a regular browser, you may be pushed to the regular sites. Tweak your user agent to pretend to be an iPhone for all the goodness.

They’re all developed in Rails, with TrueLocal running under Tomcat using JRuby.

Bring on the 11th!

Written by Tom Adams

July 10th, 2008 at 4:53 pm

Posted in Java,Ruby,Technology

Nobody *ever* uses map, et. al… (example 2)

with 2 comments

Today’s Nobody *ever* uses post.

require "netaddr.rb"
CIDR_ADDRESSES = ["192.0.2.1/24", "..."].map {|address| NetAddr::CIDR.create(address)}
in_range = CIDR_ADDRESSES.any? {|address| address.contains?("192.0.2.1")}

But of course nobody ever does this…

Written by Tom Adams

July 8th, 2008 at 11:04 am

Posted in Functional,Languages,Ruby

Tagged with ,

Nobody *ever* uses map, et. al… (example 1)

with 4 comments

Inspired by Daniel’s comment on Tony’s blog, I figured I’d start documenting the times I use “functional” constructs in my everyday work.

Consider this piece of XML, returned from an external web service:

<suggestions>
  <suggestion>
    <suggestion>paddington, NSW</suggestion>
    <location>true</location>
  </suggestion>
  <suggestion>
    <suggestion>paddington, QLD</suggestion>
    <location>true</location>
  </suggestion>
</suggestions>

Perform the following:

  1. Parse out each suggestion, turn it into an instance of Suggestion;
  2. Capitalise the first letter;
  3. Sort by name;
  4. Remove duplicates;

Here’s some Ruby code that does this, parsing by Hpricot:

class SuggestionsParser
  def self.parse(node)
    suggestions = node.search("//suggestions/suggestion").map do |s|
      Suggestion.new(s.at("suggestion").inner_text.capitalise_first_letter, s.at("location").inner_text == "true")
    end
    suggestions.sort.uniq
  end
end

But of course nobody ever does this…

Written by Tom Adams

July 2nd, 2008 at 2:14 pm

Posted in Functional,Languages,Ruby

Tagged with , , ,