TestNG NG, Next Generation of a runner for TestNG

I’ve been working with TestNG for 2 years now. The team that I work on made a decision to switch to TestNG thanks to one very important feature, @BeforeSuite and @BeforeClass. We are using Gradle as our build tool. Gradle supports TestNG tests execution.

With all the great features that TestNG comes with it also comes with features that could obfuscate test code readability. We also observed that there is no guarantee that the tests in the same class file will be executed together as a set.

With 25 minutes time of my train ride to/from work and determination to build something sweet and simple, I decided to create a Gradle plugin that will run TestNG tests in deterministic order, supporting only a small set of TestNG features.

I’ve made the code available here: https://bitbucket.org/gigu/testngng. The code is still work in progress, however there is already a functional Gradle plugin that can produce same style of XML reports as TestNG itself. There is also option of a Html report with simple and pretty style. I’ve written it in Groovy as I like Groovy. It’s Open and available to anyone.

Features supported by TestNGNG

  1. TestNGNG will recursively scan class folder passed in as parameter, in search of possible tests files. It treats this top-level folder a Suite.
  2. TestNGNG ENSURES all the tests in a class file are executed as a set of tests.
  3. TestNGNG will build a tree of tests and dependencies at the beginning of a run, before it executes a single test. The test tree is build in a form of a: One Test Suite -> Many Test Classes -> Many Tests.
  4. TestNGNG supports original TestNG annotations, it doesn’t have it’s own annotations as it is only a runner.
  5. TestNGNG support @Test annotation of a method or a class.
  6. It supports dependencies between test methods with:
    @Test(dependsOnMethods=”foo”)
  7.  It supports @BeforeSuite/Class/Test/Method and @AfterSuite/Class/Test/Method. However, @BeforeTest, @AfterTest and @BeforeMethod, @AfterMethod are treated in the same way and executed before/after each test. Just to avoid (or add to) confusion.
  8. It supports disabling of a test by enabled attribute of an annotation:
    @Test(enabled=false)

    I’m not proud of this feature though and am tempted to remove it.

  9. It supports exception expectation by expectedException attribute:
    @Test(expectedException=WhatevaException.class)
  10. TestNGNG supports data providers, however they have to be declared within the same Test Class file. Data providers could be named, or anonymous. For example:
    @Test(dataProvider = "makeMeSomeData")
      public void testWithProvider(String v1, String v2){
      System.out.println(String.format("%s - %s ", v1, v2));
    }
    @DataProvider
    public Object[][] makeMeSomeData() {
      return new Object[][]{
        {"some1", "Some2"},
        {"some3", "some4"}
       };
    }
    
  11. TestNGNG supports setup methods inherited from base classes. For example:
    public abstract class BaseForTestWithTestSetupMethods {
        public String baseValue = "";
        @BeforeMethod
        public void executeBeforeSuite() {
            baseValue = "BeforeMethod";
        }
    }
    
    public class TestClassExtendingFromBaseClass extends BaseForTestWithTestSetupMethods {
        @Test
        public void shouldPass() {
            assertThat(baseValue, is("BeforeMethod"));
        }
    }
    

Gradle plugin

Gradle plugin is very simple to use. It only requires plugin jar on a class path and TestNG as a testCompile time dependency. The plugin adds testngng task to the project. Sample use of a plugin:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath fileTree(dir: '../gradle-plugin/build/libs/', include: '*.jar')
        classpath fileTree(dir: '../testngng/build/libs/', include: '*.jar')
        classpath group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.8.0'
    }
}
apply plugin: 'java'
apply plugin: 'testngng'
repositories {
    mavenCentral()
}
dependencies {
    testCompile('org.testng:testng:6.5.1')
}

Most of the other TestNG features are not covered as they are useless and very often stand in a way of tests readability and simplicity.

Don’t ask what you test framework can do for you, ask what can you do for your test framework.

How to build the plugin and use it

You would need to checkout the project from a BitBucket and build it with Gradle by typing from command line:

gradle jar

The build jar will be used by test runner Gradle plugin inside inside the testngng_gradle_sample project. You can ran gradle command from the sample project folder:

gradle testngng

I would love to see someone having a go and providing me with some feedback. There is still a whole lot of stuff on my list that needs development in the near future, like a build tests running feedback, more plugin configurations and multiple suites per project/module.

Cheers, Greg

A same cup of Java …

… at IKEA.

 

Recently I changed the job. After three years (longest I ever worked for a single company) I left ThoughtWorks. Majority of my consultant career oscillated in .NET space. It was almost three years since last I was doing Java. New job … is Java (packed full of Java technologies).

I had to do some IKEA shopping one late afternoon after work (something for the house). As my journey turned out to be a waste of time (items out of stock) I was sitting in front of the IKEA building consuming a horrible £1.40 Hot Dog Menu 2. Watching the sun set I had a little epiphany! I started new job, I got dropped into source code and I was able to work without relearning Java, libraries and tools.

Then I realised that through three years of work at TW, C# and .NET changed it’s shape a lot. In a mean time Java did nothing,well … almost nothing. C# introduced new language syntax, features, influenced by dynamic and functional languages. Java had got annotations and generics (somehow weird generics).

Is that a bed thing? It gives stable platform, and more consistent syntax in legacy code. On the other hand it lacks cool features, and I do have to admit, I like new features. It’s like every time when Apple releases new iPhone instead of all cool new things on it all you get is better performance and stability 🙂

There is also the explosion of languages that run on JVM. I like Groovy and JRuby, I need to check out Clojure and Scala.

There was a lot of fear when Oracle purchased Sun. Next new release of Java will have closures. If it is caused by Oracle’s influence I hope for more to come.

It is about time for Java to make some tuff decisions and stop being 100% backwards compatible.

What you think? Comment me your thoughts.

Cheers, Greg

How to deal with nulls

This week I’ve been refactoring and improving some code in a .Net world. In last few weeks I also had some close encounters with Java as well. When looking at the code in both environments I realized that there is a lot of checking for null values on in a code. Where it is not a bad practice to check for null it actually presents another problem.

For someone like me when I was new to a code I couldn’t guess, what is the goal of that check. When you dealing with null the very important thing is to know where they came from and why it happened that null values occurred. When dealing with integration points it is even more important.

As you can guess code:

if (serverResponse == null)
{
    DoSomeStuff();
}

is not very descriptive. What actually happend when I got null, does it mean that there was a communication problem, error occurred or perhaps a null means that the operation was successful.

I think the best approach will be to avoid nulls if it is possible at all. Ways we could try to avoid it:
use Maybe pattern
• create Empty object values
• use Null Object pattern

Maybe pattern

I’m not sure if that is it’s appropriate name but I’ve used it on few projects and it seems like people are referring to it this way.

Have a Maybe interface and return it instead of the object itself.

interface Maybe<T>
{
    bool Hasvalue;
    T Value;
}

Also have two implementation of the interface:

public class Something<T>
{
    private readonly T _value;
    public Something(T value)
    {
        _value = value;
    }

    bool HasValue { get { return true; }  }
    T Value { get { return value; } }
}

public class Nothing<T>
{
    bool HasValue { get { return false; } }
    T Value { get { throw new InvalidOperationException(); } }
}

When returning value from an object return Maybe. Collaborator that consumes value can check if it is Something or Nothing or just ask if it has value.

Empty Object value

Just like string.Empty you can implement Empty or something similar as predefined value on your type. For example:

class Hen
{
    Egg LayEgg()
    {
        // doing stuff
        return Egg.Empty;
    }
}

class Egg
{
    public static Egg Empty = new Egg(“nothing in it”);
}

You can always check before the execution if the egg is empty.

Null object pattern

Object with no default behavior. For example:

interface TV
{
void ShowMovie();
}

class LCD : TV
{
    void ShowMovie()
    {
        // showing movie
    }
}

class Plasma : TV
{
    void ShowMovie()
    {
        // showing movie
    }
}

class NullTV : TV
{
    void ShowMovie()
    {
        // do nothing
    }
}

If something is not working well and we don’t have any of the TVs available we could return NullTV and nothing will happen.
Using the patter we can validate by type if the returned TV is a valid object and act accordingly.

I’m interested what other approaches people are heaving. Also what are the approaches in dynamic languages like Python or Ruby.

Please add your comment 😉

Greg

Percent encoding in Groovy

I was writing some helpers for OAuth Twitter authorization. One of the problem I got was the encoding. OAuth is using UTF-8 and percent encoding (special style of URL ecoding).

I couldn’t find anything build-in in Java or Groovy so I wrote a very short little method that does it.

def encodeString(def stringToEncode){

def reservedCaracters = [32:1, 33:1, 42:1, 34:1, 39:1, 40:1, 41:1, 59:1, 58:1, 64:1, 38:1, 61:1, 43:1, 36:1, 33:1, 47:1, 63:1, 37:1, 91:1, 93:1, 35:1]

def encoded =  stringToEncode.collect { letter ->
reservedCaracters[(int)letter] ? “%” +Integer.toHexString((int)letter).toString().toUpperCase() : letter
}
return encoded.join(“”)
}

If you ever need something similar, use it 😉

Greg

F1 Dashboard released

In last few months I was working on a little personal project. When Google App Engine team announced that preview of Java version is available I decided to give it a try. When I was looking for a subject of my application, one of the ideas started to emerge more that others. I was looking for a web site that could aggregate all the information about Formula 1 racing. Because there was none available (or my Google search ended on first few results that were not satisfactory) I decided to make one.

Few weeks and cups of coffee latter F1Dashboard.com is released.

F1 Dashboard screen shot
F1 Dashboard screen shot

Generalities

So, in few words, F1 Dashboard is agregator of news, and media feeds from world of Formula 1. I decided not to collect content, just store information where to find it and short description.

News are harvested from a number of web sites. Twitter updates serves as another source of news.

Images are comming from Flickr, videos from YouTube.

All updates  are happening every few minutes and are 100% automated.

Technicalities

GAE supports Groovy as one of JVM programming languages. I decided to give it a try. I love Groovy, it is somewhere in between a friendly and known Java API and Ruby programming language.

It took me a moment to use to BigTable type of DataStore. It restrictes a way I used to work with databases normaly. Google provide entire environment for local development, whitch means I don’t have to upload to a cloud to see working result.

I created a little homegrown Model Views Presenter/Controller framework and used StringTemplate as rendering engine.

jQuery is the library of choice to handle all JavaScript.

Page styling was done by a friendly and kind designer from Circa82 Michael Austin (thanks buddy).

Come on guys, give it a try and tell me what you think 😉 Feedback greatlly appriciated. http://www.f1dashboard.com

Cheerios, Greg

Groovy with JDO on Google App Engine, enhancing with DataNucleus

I have some time this days and I’m trying to fly some clouds with Google App Engine (GAE), Now when they have released Java support I can try to use Groovy. Today I tried to implement some simple storage using JDO. GAE team supports some of its features via  DataNucleus. DataNucleus is using a post compilation hook to enhance any persistable classes.

Having Groovy in a lib folder of your war (GAE runs your application from this folder) I need to put asm library as well. Latest version of Groovy (1.6.1) has a dependency on asm library in version 2.2.3. On the other hand DataNucleus enhancer has dependency on asm library in version 3.1.

GAE Java SDK is shipped with Ant task for enhancing persistable classes. It also contains Ant macro definition file that makes it simple for usage. Unfortunately this macro includes all libraries from application lib folder. This is causing Enhancer to use asm library in a version that causes it to fail massively.

[enhance] SEVERE: An error occured for ClassEnhancer "ASM" when trying to call the method "org.datanucleus.enhancer.as
m.ASMClassEnhancer" on class "getClassNameForFileName" : org.objectweb.asm.ClassReader.accept(Lorg/objectweb/asm/ClassVi
sitor;I)V

Number of this error messages is as big as the number of classes in my application.

Solution is to exclude asm library from the macro that Google shipped. Easiest way is to edit, or copy to your local application folder and use it there. The line problematic line of code is in classpath element.

<classpath>
          <pathelement path="${appengine.tools.classpath}"/>
          <pathelement path="@{war}/WEB-INF/classes"/>
          <fileset dir="@{war}/WEB-INF/lib" includes="*.jar">
          </fileset>
</classpath>

The easiest way to fix it is to exclude asm library in fileset element, just like this:

<classpath>
          <pathelement path="${appengine.tools.classpath}"/>
          <pathelement path="@{war}/WEB-INF/classes"/>
          <fileset dir="@{war}/WEB-INF/lib" includes="*.jar" excludes="asm*.jar">
          </fileset>
</classpath>

Hope that helps anyone with similar problem.

Cheers, Greg