lørdag den 3. marts 2012

Find vej i naturen

Det siges, at det bedste i hele verden er at blive fundet, når man er blevet væk; er det næstbedste så er finde noget, som man ikke vidste hvor var? Og hvad nu, hvis man endda kan kan gøre derude hvor luften er frisk og himlen er høj?

Hvis ja, så vil jeg gerne anbefale Find vej i Danmark projektet.

Projektet kommer fra Dansk Orienterings-Forbund og omfatter en lang række fine små ruter med faste poster og tilhørende gode kort. Ofte er der holdere med kort ved startstedet og kvalitet af disse er helt i top. Men de er populære, så vær forberedt på at kasserne kan være tomme når man kommer (så hent enten et kort på forhånd, tag en god udskrift med som reserve eller hav flere mulige ruter klar).

Jeg opdagede selv projektet ved et tilfælde i nærheden af Fåborg og har siden også været afsted nogle gange i skovene lige syd for Århus. Turen med start ved campingpladsen i Blommehaven kan anbefales.

Måden vi gør det på, er den børnevenlige variant som vi kalder at "gå et orienteringsløb". Det er helt grundlæggende, at der skal være god tid. Rigtig god tid, faktisk. For når man kommer væk fra stierne, så finder man ofte noget som er værd at stoppe op for at undersøge nærmere.

Og selvom stierne selvfølgelig er hovedparten af turen, så skal man regne med at komme væk fra stierne, og derfor bør man undgå habit og dansesko. Almindelig praktisk påklædning til en gåtur i skoven vil være helt fint.

Jeg vil mene at ruterne er overkommelige selv for utrænede, specielt hvis man gør sig lidt umage undervejs og har sat sig ind i andre signaturer end bare sti-billedet. Der er en fin forklaring på kortene (og hvis man er lige detajleorienteret som mig, så er her en meget grundig signaturforklaring; men man behøver altså langtfra at kunne dem alle på forhånd).



Her på billedet er Thomas i gang med at afprøve nogle af grønne nuancer på kortet; hvidt er alm. skov, medens grønt på orienteringkort brug til at angive til at angive nedsat gennemløbelighed eller gennemtrængelighed. Og det skal man have respekt for, specielt de mørkere grønne områder.

En anden signatur, som man skal have respekt for, er den blå. Jeg formåede på allermest pædagoiske vis at illustrere at de små stiplede blå streger betyder "blød bund": skoven var lige ved spise min ene sko!

Kompas bør ikke være nødvendigt, hvis man da har sin retningssans i behold og husker det gode råd om, at hvis man kommer i tvivl om hvor man er, så gå tilbage til der hvor man sidst var sikker. At prøve at støve rundt indtil man (måske) er heldig, er ikke en god metode, og ofte gør det kun ondt værre.

Ellers er det bare at komme afsted, for alle kan være med. Og husk børn, hvis man har nogle eller kan låne nogle.

søndag den 15. januar 2012

How to get Spring transactions to work with the JUnit Theories testrunner

Yes, I will make an exception and write this in English because I think the subject might have broader interest: A solution to the challenge of combining the JUnit Theories testrunner with Spring transaction support.

I am not going to say a lot about JUnit Theories (or @Rule that matter); you can google plenty of good information about that yourself. I am definitely NOT going to even try to talk about how to get Spring transactions to work with your database of choice. And I am not going to argue that it makes much sense to combine Theories and transactional databases. But, hey, challenges doesn't have to make sense to be interesting, right? :-)

And this is a challenge, because Springs support for unittest almost only works with the Spring testrunner and Theories only works if you use the Theories testrunner - and you can only have one testrunner per test. But luckily there is a way out.

So, lets see some code - and lets start with this fairly simple Spring based test:

@ContextConfiguration(locations = "classpath:testcontext.xml")
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)

public class SimpleTest {
@Autowired DataSource datasource;

private JdbcTemplate jdbcTemplate;

@Before public void setup() throws SQLException {
jdbcTemplate = new JdbcTemplate(datasource);
}

@Test
public void canInsert() throws SQLException {
jdbcTemplate.update("INSERT INTO test( id ) VALUES (?)", 1);
}
}

Note that it uses the Spring testrunner and that it wants to be transactional. Doing so makes Spring to some pretty nifty magic behind the scenes, so that everything you do to the database in a single test is wrapped in a transaction that is rolled back afterwards. Spring has even thought of starting the transaction before the @Before method and will first end it after the @After method, which is pretty clever.

But it all hinges on using the the Spring testrunner. So what if you want to use another testrunner like for instance Theories?

Well, the Spring testrunner delegates to another Spring class called TestContextManager and a fairly common workaround therefore is to do the same delegation in the @Before method as Spring would do in the testrunner. Just like this:

@ContextConfiguration(locations = "classpath:testcontext.xml")
@Transactional
@RunWith(Theories.class)
public class BuggedTheoriesTest {
@Autowired DataSource datasource;

private JdbcTemplate jdbcTemplate;

@Before public void setup() throws Exception {
//here we hook into the Spring test-support framework
final TestContextManager tcm = new TestContextManager(getClass());
tcm.prepareTestInstance(this);

//this will work for everything but spring transactions as transactions expects to be enabled before @Before

jdbcTemplate = new JdbcTemplate(datasource);
}

@Test
public void canInsert() throws SQLException {
jdbcTemplate.update("INSERT INTO test( id ) VALUES (?)", 1);
}
}

The good news is, that it actually manages to get the spring context loaded so the database is accessible. The bad news is, that we're just a tad to late for transactions to work. Remember that they were supposed to start before the @Before method? Well, the downside here is that we're too late when we try to call upon the help of Spring in the @Before method it self.

My googling skills didn't find any solution to this problem, which probably goes to say a lot about my googling skills. So I came up with the solution below (the parts of which I have found by googling :-)). I am not going to say it is particularly clever or even pretty, but hey, it seems to work!

It is based on using the @Rule annotation that was introduced in JUnit 4.7. I am not sure why it is called a "rule", but it is a mechanism that enabled you to define a wrapper that will wrap every invocation of testmethods in the test including the @Before and @After parts.

@ContextConfiguration(locations = "classpath:testcontext.xml")
@Transactional
@RunWith(Theories.class)
public class FixedTheoriesTest {
@Autowired DataSource datasource;

private JdbcTemplate jdbcTemplate;

@Rule public SpringTestContextManagerRule springTestContextManagerRule = new SpringTestContextManagerRule();

@Before public void setup() throws Exception {
jdbcTemplate = new JdbcTemplate(datasource);
}

@DataPoints public static int[] ids() {
return new int[] {1,2,5,10,20,50,100,200,500};
}

@Theory
public void canInsert(int id) throws SQLException {
jdbcTemplate.update("INSERT INTO test( id ) VALUES (?)", id);
}
}

That's all there is too it: Spring with transactions working with JUnit Theories!

Oh, and yes, you'll probably need this as well :-D :

public class SpringTestContextManagerRule implements MethodRule{

@Override
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object testInstance) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
final TestContextManager tcm = new TestContextManager(testInstance.getClass());
tcm.prepareTestInstance(testInstance);
tcm.beforeTestMethod(testInstance, frameworkMethod.getMethod());
try {
statement.evaluate();
tcm.afterTestMethod(testInstance, frameworkMethod.getMethod(), null);
} catch (Throwable t ) {
tcm.afterTestMethod(testInstance, frameworkMethod.getMethod(), t);
throw t;
}
}
};

}
}

Notice how this Rule makes a Statement that has an evaluate()-method that wraps around the statement passed to it. In that way rules can make statements that wraps statements of other rules, eventually leading to a statement wrapping an actual testmethod.

There is one caveat, though: The implementation is based on a MethodRule; this has been deprecated in later versions of JUnit, and is supposed to be replaced with a TestRule. The only problem with the new TestRule is that it will only provide you with the name of the test method to be invoked, not a reference to the method itself. It should be possible to work around this, but it is easier to use a MethodRule regardless of the deprecation warning.

I have uploaded a maven-based project to github. It should be fairly self-contained, the only real assumption is, that there is a MySQL database on localhost with a schema called testdb that can be used by the user "test".