Sunday, February 6, 2011

Parametrized Junit Tests: Postscript

In two earlier blog posts I commented on parametrized junit tests. This blog post will complement these post with an example of a piece of code.

Because all the important points are made in the other posts I will only present the Junit runner I created. A Maven project demonstrating this technique can be found code at my minimal examples repository

Without further ado: the Junit runner.

package org.junit.runners;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;

public class ParameterizedWithBuilder extends Suite
{
        private class TestClassRunnerForParametersWithBuilder extends BlockJUnit4ClassRunner
        {
                private final int fParameterSetNumber;

                private final List<Object> fParameterList;

                TestClassRunnerForParametersWithBuilder(Class<?> type, List<Object> parametersList, int i)
                        throws InitializationError
                {
                        super(type);
                        fParameterList = parametersList;
                        fParameterSetNumber = i;
                }

                @Override
                public Object createTest() throws Exception
                {
                        return getTestClass().getOnlyConstructor().newInstance(computeParams());
                }

                private Object computeParams() throws Exception
                {
                        try
                        {
                                return fParameterList.get(fParameterSetNumber);
                        }
                        catch (ClassCastException e)
                        {
                                throw new Exception(String.format("%s.%s() must return a Collection of objects.", getTestClass()
                                        .getName(), getParametersMethod(getTestClass()).getName()));
                        }
                }

                @Override
                protected String getName()
                {
                        return String.format("[%s]", fParameterSetNumber);
                }

                @Override
                protected String testName(final FrameworkMethod method)
                {
                        return String.format("%s[%s]", method.getName(), fParameterSetNumber);
                }

                @Override
                protected void validateConstructor(List<Throwable> errors)
                {
                        validateOnlyOneConstructor(errors);
                }

                @Override
                protected Statement classBlock(RunNotifier notifier)
                {
                        return childrenInvoker(notifier);
                }
        }

        private List<Runner> runners = new ArrayList<Runner>();

        public ParameterizedWithBuilder(Class<?> klass) throws Throwable
        {
                super(klass, Collections.<Runner> emptyList());
                List<Object> parametersList = getParametersList(getTestClass());
                for (int i = 0; i < parametersList.size(); i++)
                        runners.add(new TestClassRunnerForParametersWithBuilder(getTestClass().getJavaClass(), parametersList, i));

        }

        @Override
        protected List<Runner> getChildren()
        {
                return runners;
        }

        @SuppressWarnings("unchecked")
        private List<Object> getParametersList(TestClass testClass) throws Throwable
        {
                return (List<Object>) getParametersMethod(testClass).invokeExplosively(null);
        }

        private FrameworkMethod getParametersMethod(TestClass testClass) throws Exception
        {
                List<FrameworkMethod> methods = testClass.getAnnotatedMethods(Parameters.class);
                for (FrameworkMethod each : methods)
                {
                        int modifiers = each.getMethod().getModifiers();
                        if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
                                return each;
                }

                throw new Exception("No public static parameters method on class " + testClass.getName());
        }

}

Tuesday, February 1, 2011

Sexism in Language

In this blog I will point out a an examples of sexism in language.

As I pointed out in an earlier post I adapted my wife's name after we married. Although this is legally possible since the year 1998, not everybody adapted accordingly.

There are a lot of forms in which you have to fill out your name. It is often the case that the name should be the same name as found in your passport i.e. your birth name. But the forms ask to fill in your maiden name. Well the last time I checked, I never was a maiden. Furthermore, I have no intention of ever becoming one. So I regard this as a strange question.

The origins of the use of this language are clear to me. A long time ago only women could take on an other name. So if someone wanted to know your birth name she could reason as follows:

  1. Males can be asked for their name, regardless of their marital status.
  2. Females can be asked for their name, unless they are married. Then they should be asked for their maiden name.

But since the 1998 this rule does not apply any more. And if you want to know my birth name ask for it. It is been twelve years, everybody had enough time change their forms. I regard this as a very sexist use of language.

Sunday, January 30, 2011

Parametrized JUnit Tests Revisited

In the Parametrized JUnit Tests blog post I explained how to create a parametrized junit test. In this blog post I will discuss the reaction of one of my colleagues.

After reading my blog post about parametrized junit tests a colleague expressed his objections with this way of testing. He was a bit disappointed with one thing in particular. The signature of the public static method that is used to construct the test.

@Parameters
public static Collection<Object[]> data()

Is returns a collection of Object arrays. One Object array for each set of parameters. The reason this should be an Object array becomes clear from it's usage.

List<Object[]> data = new ArrayList<Object[]>();
data.add(new Object[] { 2, new Integer[] { 2 } });
return data;

Because the parameters used are of different type, in this case an Integer and an Integer array, they only super-type they have in common is Object.

The objection of my colleague was that is berefts the compiler of the oppertunity to detect type errors at compile time. The compiler would happily compile the following code. But it would blow up at run time.

List<Object[]> data = new ArrayList<Object[]>();
data.add(new Object[] { 2, new Integer[] { 2 } });
data.add(new Object[] { 2, new Double[] { 2.0 } });
return data;

After some discussion with my colleague we came up with the following solution. Instead of using a lot of parameters in the constructor, use only one. By using the builder pattern one retains the type information. Furthermore because now only one parameter is needed, the nearest super-type of all the parameters is the type of the parameter itself.

The code that follows show the same test as in the previous blog post. The change is reflected in the use of the builder pattern. Note that a fluent interface is used to easily construct a builder for the test.
One could still object that the array is now superfluous. They are correct. One way to deal with their objections is to write an custom runner.

@RunWith(Parameterized.class)
public class FactorizationTest
{
    private int number;

    private List<Integer> expectedResult;

    public FactorizationTest(FactorizationTestBuilder builder)
    {
        this.number = builder.getNumber();
        this.expectedResult = builder.getExpectedResult();
    }

    @Test
    public void factorize()
    {
        assertEquals(expectedResult, Factorization.factor(number));
    }

    @Parameters
    public static Collection<FactorizationTestBuilder[]> data()
    {
        List<FactorizationTestBuilder[]> data = new ArrayList<FactorizationTestBuilder[]>();
        data.add(new FactorizationTestBuilder[] { FactorizationTestBuilder.withNumber(2).expect(2) });
        data.add(new FactorizationTestBuilder[] { FactorizationTestBuilder.withNumber(8).expect(2, 2, 2) });
        data.add(new FactorizationTestBuilder[] { FactorizationTestBuilder.withNumber(9).expect(3, 3) });
        data.add(new FactorizationTestBuilder[] { FactorizationTestBuilder.withNumber(72).expect(2, 2, 2, 3, 3) });
        return data;
      }
}

class FactorizationTestBuilder
{
    private int number;

    private List<Integer> expectedResult = new ArrayList<Integer>();

    public static FactorizationTestBuilder withNumber(int number)
    {
        return new FactorizationTestBuilder(number);
    }

    private FactorizationTestBuilder(int number)
    {
        this.number = number;
    }

    public FactorizationTestBuilder expect(Integer... expectedResult)
    {
        this.expectedResult = Arrays.asList(expectedResult);
        return this;
    }

    public int getNumber()
    {
        return number;
    }

    public List<Integer> getExpectedResult()
    {
        return expectedResult;
    }
}

In this blog post I described the objections of a colleague on the previous Parametrized Junit Test blog. I have shown had to meet these objections by using the builder pattern.

Wednesday, January 26, 2011

Updated old post

In this blog post I announced that I switched to using Mathjax. But I hadn't got to the point of rewriting my old post, with this new interface.

Coming this spring I set out to rectify this point and now all posts are using Mathjax as Latex rendering engine.

The only thing I noticed that not every post is using proper html. So probably I have to go back and change that to.

Saturday, January 15, 2011

Parametrized JUnit tests

In this post I will examine parametrized JUnit tests.

With the introduction of Junit 4, a lot has changed for testing Java software with Junit. One of the more esoteric additions are parametrized tests. It allows a developer to run a great deal of test which differ only in a set of parameters. Without further ado I will show you a parametrized test.

@RunWith(Parameterized.class)
public class FactorizationTest
{
    private int number;

    private List expectedResult;

    public FactorizationTest(int number, Integer[] result)
    {
        this.number = number;
        this.expectedResult = Arrays.asList(result);
    }

    @Test
    public void factorize()
    {
        assertEquals(expectedResult, Factorization.factor(number));
    }

    @Parameters
    public static Collection<Object[]> data()  
    {   
        List<Object[]> data = new ArrayList<Object[]>();
        data.add(new Object[] { 2, new Integer[] { 2 } });
        data.add(new Object[] { 8, new Integer[] { 2, 2, 2 } });
        data.add(new Object[] { 9, new Integer[] { 3, 3 } });
        data.add(new Object[] { 72, new Integer[] { 2, 2, 2, 3, 3 } });   
        return data;
    }
} 

Lets focus on line 17 of the method annotated with @Test. This method asserts that the expectedResult is returned by the static method Factorization.factor(int) which is called with parameter number. Both expectedResult and number are private fields of the class FactorizationTest. The fields are assigned in the constructor.

By annotating the class with the @RunWith(Parameterized.class) we are telling Junit to run this class with the Parameterized Runner. By implementing a Runner you can specify how to run the tests.

For the Parameterized this means the following. (The following section is paraphrased. See https://github.com/KentBeck/junit for the details.)

  1. Get an Collection of Object-arrays.
  2. Repeat for every Object-array in the collection:
    1. Construct an instance of FactorizationTest passing as parameters the various elements in the Object-array.
    2. Run all methods annotated with @Test.

The collection mentioned in step 1 is obtained by calling a method annotated with @Parameters. So in this example the following facts will be asserted.

numberfactors
22
82, 2, 2
93, 3
722, 2, 2, 3, 3

In this blog post I made clear how to use parameterized test in the Junit test framework.

Thursday, November 18, 2010

Determine when to accept a double in backgammon

In this blog post I will examine the precise conditions when to accept a double in backgammon.

The question and it's answer whether to accept a double probably is a classical result in backgammon. Guided by mathematics it is primarily concerned with the expected value of a game.

To recap: If you win a game normally you win the amount indicated by the doubling cube. If you win a gammon i.e. without your opponent bearing off a single checker, you win twice the amount on the doubling cube. If the opponent hasn't borne off any checkers and still has checkers in your home board you win a backgammon and gain triple the amount indicated by the doubling cube.

Let's assume the change of winning the game normally is \(p_{n}\), that of winning a gammon is \(p_{g}\) and that of winning a backgammon is \(p_{b}\). In similar fashion define the chances of losing as \(q_{n},\,q_{g}\) and \(q_{b}\).
Furthermore, let\(v\) be the current value of the doubling cube.

If your opponent offers you a double and you refuse you lose \(-v\) points, guaranteed. But if you accept the double the expected value will be

\[
2vp_{n} + 4vp_{g} + 6vp_{b} - 2vq_{n} - 4vq_{g} - 6vq_{b} = 2v((p_{n} - q_{n}) + 2(p_{g} - q_{g}) + 3(p_{b} - q_{b}))
\]

So you should accept a double if the above expression is greater then \(-v\).

Lets further assume that the changes of losing are winning a gammon are backgammon are zero. Then the above equality simplifies (using the relation \(q_{n} = 1-p_{n}\)) to \(2p_{n}-1 \ge -\frac{1}{2}\) or \(p_{n} \ge \frac{1}{4}\). This is a very classic result of backgammon. For example, it is stated, without proof, in 501 essential backgammon problems, considered to be the bible of backgammon.

In order to gain an other insight we assume that the changes of winning or losing a backgammon or winning a gammon are zero, but losing a backgammon is a possibility. (For example your trapped on the bar while your opponent already beared off succesfully at least one checker.)
The above equations reduces to \(p_{n}-q_{n}-2q_{g} \ge -\frac{1}{2}\). Now the relation \(p_{n} + q_{n} + q_{g} = 1\) tells use that \(q_{n} = 1 - p_{n} - q_{g}\). This simplifies our equations to \(p_{n} \ge \frac{1}{4} + \frac{1}{2}q_{g}\). This tells use you have to have a greater change of winning if your are to accept a double when there is a change of losing a gammon.

The above equations and a keen insight in the chances at the backgammon board can help to guide your decision of taking a double or not.
In an other blog I will investigate the conditions of offering a double.

MinuteMath: A bite size math problem a day

I Recently subscribed to the The Mathematical Association of America twitter feed. The most important reason for me is their daily MinuteMath.

The MinuteMath is a daily bite size mathematical problem of varying difficulty. All the problems are multiple choice and hints, solutions and classifications are given.

It is a fun way to distract your mind for a moment and figure out a interesting little problem. If your interested start following @maanow.