jastrachan | 13 Jul 14:24 2004

Re: [groovy-dev] Bruce Eckel's talk & easier unit testing...

On 13 Jul 2004, at 11:35, Jakob Praher wrote:
> Am Die, den 13.07.2004 schrieb jastrachan@... um 11:11:
>> While watching Bruce Eckel's talk
>> http://mindview.net/WebLog/log-0055
> I saw that too. Great talk, I liked the discussion of generics and
> dynamic typing stuff.

Agreed - it put me even further off generics - too much complexity for 
too little gain. What with nicer iteration syntax to hide the casts 
(which dynamic typing does too) we mostly just need cardinality 
metadata. (reflection on 1-many relationships in beans).

>> it got me thinking that it'd be really cool to be able to type
>> something like the following and use it as a unit test case...
>>      foo = new Foo(123)
>>      foo.doSomething("hello")
>>      assert foo.cheese == "cheddar"
> I think this is good.
>> i.e. just write a chunk of code as being an individual unit test case.
>> This works fine for real simple stuff - if you want to get complex,
>> write a class with setUp() / tearDown() methods and the like. The
>> tricky thing is the above script won't generate a class which is-a
>> JUnit TestCase and so if this were compiled to bytecode the usual 
>> JUnit
>> test runner tools might not pick it up.
> you could write a SimpleGroovyTestletTestCaseWrapper or something like
> that. this TestCase looks like
> class TestCaseWrapper extends junit.framework.TestCase {
> 	GroovyObject groovyObject;	
> 	public void setUp( ) {
> 		// load groovyObject from Systemproperty
> 		String fileName = System.getProperty( "GUNIT" );
> 	}
> 	public void testIt( ) {
> 		// run the groovyObject ....
> 	}
> }
> java TestRunner -DGUNIT=foo/bar.groovy


We've already got the GroovyTestSuite class which can do this...


Which up to now only worked if the groovy script implemented TestCase  
(e.g. extending from GroovyTestCase)

I've gone ahead and patched it so that you can pass along any groovy 
script and its ran as a single Test inside JUnit. e.g.

java groovy.util.GroovyTestSuite 

which is a nice workaround for now. Works fine in an IDE.

> Or one could do it as you said with byte code manipulation, which
> shouldn't be too hard, since the only thing that must be adapted is the
> file name ....


>> I'm wondering if this actually matters. e.g. we could run this from 
>> the
>> command line whenever we like...
>> groovy MyTest.groovy
>> and if we get any exceptions, then its failed :). In this case the
>> script = 1 test, so there's no real need to use a TestCase etc. So
>> maybe we could have a form of the Ant <junit> task which as well as
>> looking for TestCase instances, could also gracefully handle scripts 
>> as
>> above, which would all implement Runnable, so we just treat the run()
>> method as one test etc.
>> Though writing all that plumbing & hacking of Ant tasks doesn't sound
>> like fun. So another idea could be to somehow mutate the script to be
>> derived from TestCase, using some magic mechanism. e.g. if we 
>> supported
>> AST level macros, we could maybe use a macro to change the base class
>> of the script such that it actually created a TestCase with a main
>> which ran the script. I guess that'd be the ideal, then it really
>> would, at the bytecode level, be a TestCase and so work with any JUnit
>> capable code. I'm not sure yet what the macro should look like but
>> imagine its something like...
> AST level macros should be interesting. If you are able to do allow a
> clear separation of macros and the core AST Parser everything is fine. 
> I
> think one constraint on this is that it AST Macro handling should not
> impede the parser performance too much.

Agreed. I'm not sure yet what syntax to use either. One obvious one is 
to use annotations like syntax, to make clear macro calls from the rest 
of the language. At least it'd be familiar to Java developers; though I 
confess to not being super-keen on the syntax.

> some ideas for a generic way of wrapping:
> wrap( Baseclass.method ) {
> }
> which would wrap the bytecode into a class that extends Baseclas inside
> a method called "method", I think it's generic enough, on the other 
> hand
> a clever macro stuff could be interesting. but i know a little bit the
> structure of gcc, and too much magic at the parsing level will
> eventually introduce many dependencies of one module on the other, and
> this will harden parser improvements ....
> anyway an example:
> wrap into ( TestCase.testFoo ) {
> 	foo = new Foo( 123 );
> 	foo.doSomething( "hello" );
> 	assert foo.cheese == "cheddar"
> }
> or more elegantly:
> void TestCase.testFoo( ) {
> 	foo = new Foo( 123 );
> 	foo.doSomething( "hello" );
> 	assert foo.cheese == "cheddar"
> }
> which would "know" that this class should extend TestCase ....
> On the other hand, I don't have looked into the macro stuff. So it
> perhaps is good enough to support it.

Actually thats quite neat.

void GroovyTestCase.testFoo() {
     ... // use all the groovy helper methods here ...

> is the use keywoard related to macros?

Not really, at the moment it just adds new helper methods to objects.