You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-dev@db.apache.org by "Jean T. Anderson" <jt...@bristowhill.com> on 2007/02/08 19:46:14 UTC

[JUnit] How CleanDatabaseTestSetup.decorateSQL works

When I first starting working on the junit conversion for callable.java
(DERBY-2304) I had spotted the advice below in
http://wiki.apache.org/db-derby/KillDerbyTestHarness :

> How to execute DDL at setUp that is dropped automatically at tearDown?
> 
> Provide a class that extends CleanDatabaseTestSetup and implement the decorateSQL method. This can be achieved as an inner class, search for references to CleanDatabaseTestSetup for examples.

To be honest, I had trouble understanding how decorateSQL worked. I did
get it working and thought I'd document my {mis}understanding here.
Maybe those who set up this junit test framework can correct and
clarify. If I can nail this info down, I'll then add it to the Wiki to
help the next person spinning up.

Given this goal:

A. Create SQL objects at the start of the test run
B. Reset those objects for each fixture
C. Drop SQL objects at the end of the test run

First of all, is this goal generally desirable? I think it is because
creating/dropping SQL objects for each fixture in a test probably won't
scale as we add more and more tests.

To satisfy this goal, the methods below need to be implemented (see
Dan's DERBY-2304 comment especially about automating B below [1]):

A. Create objects: code CleanDatabaseTestSetup.decorateSQL to do this
B. Reset objects: code setUp() to do this
C. Drop objects: you don't need to code anything --
CleanDatabaseTestSetup automagically does it for you.

The trickiest thing for me was understanding how to implement
CleanDatabaseTestSetup.decorateSQL, in part because I didn't see what
needed to be explicitly invoked and what would be automatically invoked
by the framework. I adopted the ProcedureTest.java approach and probably
my terminology isn't spot on for a description, but here is my
understanding of how it works:

1) The junit framework invokes the suite() method.

2) The suite() method should be coded to explicitly invoke addTest on
its own method that does whatever setup is needed -- ProcedureTest.java
calls this method baseSuite() and I did the same, but you can call it
anything you want because *you're* the one invoking it.

The suite() method is coded to explicitly call
suite.addTest(baseSuite()) twice: once for embedded and once for client.

Here's what the baseSuite() method does (should do?):

 a) creates the TestSuite
 b) adds the test's class to it, which will add all methods whose name
starts with "test"
 c) optionally adds any platform-specific tests. If you avoid prepending
"test" to the method name, step b won't automatically add it and you can
explicitly add it yourself.
 d) explicitly invokes a nested CleanDatabaseTestSetup, which creates
the decorateSQL method.
 e) The decorateSQL method creates the database objects

3) The junit framework invokes that decorateSQL method

Is this a good way to do it? or should anything change about it?

thanks in advance for corrections and clarifications,

 -jean

[1] https://issues.apache.org/jira/browse/DERBY-2304#action_12471070

Re: [JUnit] How CleanDatabaseTestSetup.decorateSQL works

Posted by "Jean T. Anderson" <jt...@bristowhill.com>.
thanks for the excellent feedback, Dan. I'll summarize on the wiki in
just over a week (will be at a conference tomorrow then out next week
but with some email access). So anyone feel free to add more wisdom,
clarifications, etc. and I'll consolidate it all when I get back.

-jean

Daniel John Debrunner wrote:
> Jean T. Anderson wrote:
> 
>> When I first starting working on the junit conversion for callable.java
>> (DERBY-2304) I had spotted the advice below in
>> http://wiki.apache.org/db-derby/KillDerbyTestHarness :
>>
>>> How to execute DDL at setUp that is dropped automatically at tearDown?
>>>
>>> Provide a class that extends CleanDatabaseTestSetup and implement the
>>> decorateSQL method. This can be achieved as an inner class, search
>>> for references to CleanDatabaseTestSetup for examples.
> 
> 
>>  d) explicitly invokes a nested CleanDatabaseTestSetup, which creates
>> the decorateSQL method.
> 
>>  e) The decorateSQL method creates the database objects
> 
> To tie the quote from the wiki and d) together I think d) & e) could be
> reworded, though I think you know what is going on.
> 
> d) decorate your test with an (instance of an) anonymous inner class
> that extends CleanDatabaseTestSetup and implements a decorateSQL method
> that creates the database objects and populates any tables as required.
> 
> Just that your version could imply that the decorateSQL method is
> created by running the suite method (it isn't, the compiler does that)
> and that it's run by the suite method (use of invoke).
> 
> Of course that may not be clearer than the original on the wiki. :-)
> 
>> 3) The junit framework invokes that decorateSQL method
> 
> 
> Technically true (and maybe false as well :-), but I think somewhat
> misleading.
> 
> JUnit is Object Oriented, test runners only knows about Tests, they just
> runs Tests, ie perform the "run action" of that Test. However, the test
> runners know nothing of what happens when these are run, they just make
> sure that the Test is run. This is one of the beauties of JUnit.
> 
> There are different types of Tests, the three typically used in Derby
> are fixtures, suites and decorators.
> 
> A fixture is an instance of a class and a public void method in that
> class. Its run action is to:
>       1) call setUp() method
>       2) call fixture method (e.g. testInsertStatement())
>       3) call tearDown() method
> 
> A suite is just a list of other Tests (not just fixtures, but any type
> of Test). Its run action is to:
>      1) for each Test in its list: perform the run action of that Test.
> 
> A decorator is an instance of a class and another Test (again any type
> of Test). Its run action is to:
>       1) call its (the decorator's) setUp method
>       2) perform the run action of its Test
>       3) call its (the decorator's) tearDown method
> 
> (I guess it decorates the Test by adding "frills" around it?)
> 
> So to look at CleanDatabaseTestSetup we can see from its javadoc that
> its specific run action is:
>   1a) clean the database
>   1b) call decorateSQL (which does nothing)
>   1c) call commit
>   2) perform the run action of its Test
>   3) clean the database
> 
> Now if I have an anonymous inner class that extends
> CleanDatabaseTestSetup and provides a decorateSQL method then its run
> action is:
>   1a) clean the database
>   1b) call decorateSQL which creates the required database state.
>   1c) call commit
>   2) perform the run action of its Test
>   3) clean the database
> 
> So technically it is not JUnit that is calling decorateSQL, but instead
> CleanDatabaseTestSetup which is a decorator and thus just a Test.
> 
> HTH,
> Dan.
> 


Re: [JUnit] How CleanDatabaseTestSetup.decorateSQL works

Posted by Daniel John Debrunner <dj...@apache.org>.
Jean T. Anderson wrote:
> When I first starting working on the junit conversion for callable.java
> (DERBY-2304) I had spotted the advice below in
> http://wiki.apache.org/db-derby/KillDerbyTestHarness :
> 
>> How to execute DDL at setUp that is dropped automatically at tearDown?
>>
>> Provide a class that extends CleanDatabaseTestSetup and implement the decorateSQL method. This can be achieved as an inner class, search for references to CleanDatabaseTestSetup for examples.

>  d) explicitly invokes a nested CleanDatabaseTestSetup, which creates
> the decorateSQL method.
 >  e) The decorateSQL method creates the database objects

To tie the quote from the wiki and d) together I think d) & e) could be 
reworded, though I think you know what is going on.

d) decorate your test with an (instance of an) anonymous inner class 
that extends CleanDatabaseTestSetup and implements a decorateSQL method 
that creates the database objects and populates any tables as required.

Just that your version could imply that the decorateSQL method is 
created by running the suite method (it isn't, the compiler does that) 
and that it's run by the suite method (use of invoke).

Of course that may not be clearer than the original on the wiki. :-)

> 3) The junit framework invokes that decorateSQL method

Technically true (and maybe false as well :-), but I think somewhat 
misleading.

JUnit is Object Oriented, test runners only knows about Tests, they just 
runs Tests, ie perform the "run action" of that Test. However, the test 
runners know nothing of what happens when these are run, they just make 
sure that the Test is run. This is one of the beauties of JUnit.

There are different types of Tests, the three typically used in Derby 
are fixtures, suites and decorators.

A fixture is an instance of a class and a public void method in that 
class. Its run action is to:
       1) call setUp() method
       2) call fixture method (e.g. testInsertStatement())
       3) call tearDown() method

A suite is just a list of other Tests (not just fixtures, but any type 
of Test). Its run action is to:
      1) for each Test in its list: perform the run action of that Test.

A decorator is an instance of a class and another Test (again any type 
of Test). Its run action is to:
       1) call its (the decorator's) setUp method
       2) perform the run action of its Test
       3) call its (the decorator's) tearDown method

(I guess it decorates the Test by adding "frills" around it?)

So to look at CleanDatabaseTestSetup we can see from its javadoc that 
its specific run action is:
   1a) clean the database
   1b) call decorateSQL (which does nothing)
   1c) call commit
   2) perform the run action of its Test
   3) clean the database

Now if I have an anonymous inner class that extends 
CleanDatabaseTestSetup and provides a decorateSQL method then its run 
action is:
   1a) clean the database
   1b) call decorateSQL which creates the required database state.
   1c) call commit
   2) perform the run action of its Test
   3) clean the database

So technically it is not JUnit that is calling decorateSQL, but instead 
CleanDatabaseTestSetup which is a decorator and thus just a Test.

HTH,
Dan.