Showing posts with label techniques. Show all posts
Showing posts with label techniques. Show all posts

Saturday, 26 July 2008

Parameterised Testing with JUnit 4

Anybody who's ever written software more complex than the typical Hello, World! examples knows that software without bugs doesn't exist and that it needs to be tested. Most people who have ever done testing on programs written in the Java language have come across JUnit. Now, JUnit is a very small package. In fact, when you look at the number of classes provided you'd think it doesn't do anything useful. But don't be fooled, in this small amount of code lies extreme power and flexibility. Even more so since JUnit 4 that makes full use of the power of annotations, introduced in Java 5.0.

Typically, when using JUnit 3, you'd create one test case class per class you want to test and one test method per method you want to test. The problem is, as soon as your method takes a parameter, it is likely that you will want to test your method with a variety of values for this parameter: normal and invalid values as well as border conditions. In the old days, you had two ways to do it:

  • Test the same method with several different parameters in a single test: it works but all your tests with different values are bundled into a single test when it comes to output. And if you have 100 error conditions and it fails on the second one, you don't know whether any of the remaining 98 work.
  • Create one method per parameter variation you want to try: you can then report each test condition individually but it can be difficult to tell when they are related to the same method. And it requires a stupid amount of extra code.

There must be a better way to do this. And JUnit 4 has the answer: parameterised tests. So how does it work? Let's take a real life example. I've been playing with the new script package in Java 6.0 to create a basic Forth language interpreter in Java. So far, I can do the four basic arithmetic operations and print stuff off the stack. That sort of code is the ideal candidate for parameterised testing as I'd want to test my eval method with a number of different scripts without having to write one single method for each test script. So, the JUnit test class I started from looked something like this:

<some more imports go here...>

import static org.junit.Assert.*;
import org.junit.Test;

public class JForthScriptEngineTest {

 @Before
 public void setUp() throws Exception {
  jforthEngineFactory = new JForthScriptEngineFactory();
  jforthEngine = jforthEngineFactory.getScriptEngine();
 }

 @After
 public void tearDown() throws Exception {
  jforthEngine = null;
  jforthEngineFactory = null;
 }

 @Test
 public void testEvalReaderScriptContext() throws ScriptException {
  // context
  String script = "2 3 + .";
  String expectedResult = "5 ";
  ScriptContext context = new SimpleScriptContext();
  StringWriter out = new StringWriter();
  context.setWriter(out);
  // script
  StringReader in = new StringReader(script);
  Object r = jforthEngine.eval(in, context);
  assertEquals("Unexpected script output", expectedResult,
   out.toString());
 }

 @Test
 public void testGetFactory() {
  ScriptEngine engine = new JForthScriptEngine();
  ScriptEngineFactory factory = engine.getFactory();
  assertEquals(JForthScriptEngineFactory.class, factory.getClass());
 }

 private ScriptEngine jforthEngine;
 
 private ScriptEngineFactory jforthEngineFactory;
}

My testEvalReaderScriptContext method was exactly the sort of things that should be parameterised. The solution was to extract that method from this test class and create a new parameterised test class:

<some more imports go here...>

import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class ParameterizedJForthScriptEngineTest {
 @Parameters
 public static Collection<String[]> data() {
  return Arrays.asList(new String[][] {
    { "2 3 + .", "5 " },
    { "2 3 * .", "6 " }
  }
  );
 }
 
 public ParameterizedJForthScriptEngineTest(
   String script, String expectedResult) {
  this.script = script;
  this.expectedResult = expectedResult;
 }

 @Before
 public void setUp() throws Exception {
  jforthEngineFactory = new JForthScriptEngineFactory();
  jforthEngine = jforthEngineFactory.getScriptEngine();
 }

 @After
 public void tearDown() throws Exception {
  jforthEngine = null;
  jforthEngineFactory = null;
 }

 @Test
 public void testEvalReaderScriptContext() throws ScriptException {
  // context
  ScriptContext context = new SimpleScriptContext();
  StringWriter out = new StringWriter();
  context.setWriter(out);
  // script
  StringReader in = new StringReader(script);
  Object r = jforthEngine.eval(in, context);
  assertEquals("Unexpected script output", expectedResult,
   out.toString());
 }

 private String script;
 
 private String expectedResult;

 private ScriptEngine jforthEngine;
 
 private ScriptEngineFactory jforthEngineFactory;
}

The annotation before the class declaration tells it to run with a custom runner, in this case, the Parameterized one. Then the @Parameters annotation tells the runner what method will return a collection of parameters that can then be passed to the constructor in sequence. In my case, each entry in the collection is an array with two String values which is what the constructor takes. If I want to add more test conditions, I can just add more values in that collection. Of course, you could also write the data() method so that it reads from a set of files rather than hard code the test conditions and then you will reach testing nirvana: complete separation between tested code, testing code and test data!

So there you have it again: size doesn't matter, it's what you put in your code that does. JUnit is a very small package that packs enormous power. Use it early, use it often. It even makes testing fun! Did I just say that?

Update

I added the ability to produce compiled scripts in my Forth engine today, in addition to straight evaluation. I added a new test method in ParameterizedJForthScriptEngineTest and all parameterised tests are now run through both methods without having to do anything. What's better, I can immediately see what test data work in one case but not the other.

Sunday, 17 June 2007

How to create a colour palette from a photograph using Photoshop

Following a talk by John Hicks at @media2007, I was wondering how to derive a colour palette from a photograph in Photoshop. As I am a real Photoshop novice, I started by searching through the help and eventually came to a technique that involving transforming the image to indexed colour mode, reducing the number of colours and creating a swatch library from the resulting image. The results were quite poor and it was very cumbersome to do. There had to be a better way.

So I ditched the Photoshop manual and went googling. It took about 5 minutes to come up with the answer: pixelate the picture, as explained graphically on Upstart Blogger from the original article at YourTotalSite. Here is the result with one of my pictures:

Pixelated photograph to extract its colour palette

Pixelated photograph to extract its colour palette

The cool thing about this technique is that it is very fast and you can manipulate the resulting colour palette as an image. Of course, if you want to, you can always extract a swatch library out of it as you would have done in the original picture.

Update: Of course, as I had just published this article I had a brain wave and decided to check out fd's flickr toys. As you would expect, they have a palette generator that does exactly what it says on the tin and gives you a 15 colour palette with hexadecimal codes and an example CSS snippet.

Screenshot of fd's flickr toys palette generator output

Screenshot of fd's flickr toys palette generator output

Sunday, 24 September 2006

White Balance

Three images showing different white balance settings

Digital cameras have one very interesting advantage over good old film cameras: you can adjust settings that you would normally have adjusted by changing film. An obvious one is the ISO setting: one shot can be taken at 100 ASA, the next one at 400. A less obvious but very important setting is the white balance. This setting is meant to adjust the colour balance in different types of light so that white areas actually come out white. If you get the white balance wrong, the white areas in your shot will come out yellow or blue, depending which way you got it wrong.

Most DSLR cameras and some high end compact digital ones allow you to override the white balance, typically by offering a presets for tungsten or fluorescent light, cloudy or shade conditions, etc. But your specific lighting conditions don’t always match a preset. Some cameras allow you to provide a sun temperature equivalent in Kelvin but this is confusing if you are not an astronomer or a physicist. Finally some cameras allow you to specify a custom white balance by giving them a reference. I had never used this setting as I wasn’t too sure how it worked on my camera, until today when I picked up a copy of Mac User that has a very simple and straightforward explanation.

I decided that the subject for experimentation would be my bedroom, complete with unmade bed. Not that I want to pretend I am Tracey Emin but the wall behind my bed is the best white reference in my flat. To make my life easier, I composed the shot to ensure a large area of white wall would cover the centre of the image, as this is the area the camera will use as white reference.

  • The first picture is taken using the automatic white balance setting. Although the camera tried to compensate for the yellow hue produced by the tungsten light, it is still very yellow.
  • The second picture is taken with a preset white balance for tungsten light, which should be the right setting in this case. unfortunately, and probably because of the lamp shade that modifies the light, it is still quite yellow. Although, in this case, when seen on its own and in the original light, the mind adjusts and makes you think it is actually white.
  • The last picture was taken using the custom white balance seting and the previous picture as a reference. This time it is really white: I verified this by using the colour picker tool in Photoshop. The funny thing though is that seeing the shot on the camera’s LCD screen, on its own and just after the previous one, the mind plays tricks again and makes you think it is blue-ish.

Using a custom white balance produces great results. The only complication is that you have to take a reference shot and adjust the setting every time you change light condition but it is easier and quicker than doing that in Photoshop afterwards, especially if you take several shots in the same lighting conditions. Also note that, because it consists in comparing the balance of primary colours in a reference subject, this reference doesn’t have to be pure white, it can be light grey. So a photographic 18% grey card is an ideal reference object.