Loading ...
Sorry, an error occurred while loading the content.
 

Re: [junit] Re: JUnit Design?

Expand Messages
  • Robert Bateman
    Levi, I tried this - it doesn t work :( My emperical evidence from using JUnit indicates that setUp() and tearDown() are pretty much called before *each* test.
    Message 1 of 27 , Mar 26, 2003
      Levi,

      I tried this - it doesn't work :(

      My emperical evidence from using JUnit indicates that setUp() and tearDown() are pretty much
      called before *each* test. This, in effect, makes each test case an isolated entity.

      Someone else mentioned the FAQ entry that basically runs the test suite for you with your code
      manually running the setUp() and tearDown() routines only once. The FAQ entry uses a test Suite
      to test with. I believe the test Suite example was simplified so we can run all tests via run(
      test.class ) in main().

      I haven't seen anything that refactors the FAQ entry to use the newer execution method. I hope to
      have enough time soon to try and figure out how to do this myself.

      Bob
      --- Levi Cook <levicook@...> wrote:
      > Once you've gone static, I could imagine this sort of hackery... (I don't endorse it though:)
      >
      > SomeTest extends TestCase
      > {
      > static Connection myConnection = null
      > static int numTestsRun = 0
      >
      > protected void setUp()
      > {
      > if (myConnection == null)
      > myConnection = createMyConnection()
      > }
      >
      > public void testA(){}
      > public void testB(){}
      > public void testC(){}
      >
      > protected void tearDown()
      > {
      > numTestsRun++;
      > if(numTestsRun == countTestCases())
      > release(myConnection)
      > }
      >
      > private Connection createMyConnection()
      > {
      > // do something "expensive"
      > }
      >
      > private release(Connection theConnection)
      > {
      > // do the good citizen clean up thing...
      > }
      > }
      >
      >
      > -- Levi
      >
      >
      >
      > Bill Venners wrote:
      >
      > >Bob,
      > >
      > >On Sunday, March 23, 2003, at 11:29 AM, Robert Bateman wrote:
      > >
      > >
      > >
      > >>--- Bill Venners <bv@...> wrote:
      > >>
      > >>
      > >>>If the fixture includes an expensive database
      > >>>connection, for example, could that connection not be created by the
      > >>>first test method and stored in a static variable for all subsequent
      > >>>test methods to share? Not sure how you could close the connection at
      > >>>the end of the last test method executed, though. Has anyone used
      > >>>static variables to share fixture objects among multiple test methods?
      > >>>
      > >>>
      > >>I did this very thing by accident - as I'm new to JUnit testing.
      > >>
      > >>I have legacy DB code I have to test and the original author used a
      > >>static anonymous class to
      > >>create the connection cache. I use setup() to instantiate the
      > >>underlying class and get/close my
      > >>DB connections in each test. I pay the penalty for the connection
      > >>creation in the first test, but
      > >>every other test is fairly fast.
      > >>
      > >>
      > >>So far, I've found JUnits testing of each test method to be low level
      > >>in design and nature... I
      > >>create a method in an object and my test methods exercise my method -
      > >>checking for validity of
      > >>execution. I've found JUnit assumes I'm interested in assuring the
      > >>tested method executes and
      > >>provides some specific result.
      > >>
      > >>Maybe I'm still too new to JUnit to know what I'm missing with
      > >>SuiteRunner - but I've always
      > >>thought the first test I must *always* perform is the validation of my
      > >>code against the
      > >>specifications - that what I'm writing is performing to expectations.
      > >>
      > >>Your right, if I write code that modifies a part of my object in some
      > >>way, I need to insure that I
      > >>haven't created an artifact that can damage some other part of the
      > >>code. Isn't that the basis of
      > >>performing lots of different asserts in each of your tests? If I can
      > >>alter some part of my object
      > >>thru my code, then after my code runs, don't I want to verify the
      > >>contents of the underlying
      > >>object? All within one test? (Not Suite of tests - but an individual
      > >>test...)
      > >>
      > >>If I'm too far off topic, please forgive me.
      > >>
      > >>
      > >>
      > >Not off topic at all. I was asking if anyone had used static members to
      > >share fixture among multiple test methods in a single TestCase, and you
      > >did. You even did it for a database connection, which was the example I
      > >mentioned. The one question I still have about your test code is, did
      > >you find a way to explicitly close the connection after the last test
      > >method finished? Or was it just left open under the assumption your app
      > >would go away soon enough.
      > >
      > >One significant difference between the static member approach to
      > >fixture sharing in JUnit and SuiteRunner is that I know how to close
      > >the connection when I'm done in SuiteRunner, but not in JUnit. If
      > >anyone has a way to do that, please reply.
      > >
      > >Another difference is really one of design taste I suspect. I just
      > >found it non-intuitive that JUnit gave each test method invocation its
      > >own instance, especially when they also provided the setUp() method. I
      > >used JUnit a long time before I realized this object wrapping was going
      > >on. In a previous post to this list, I asked if anyone could help me
      > >understand what benefit I get for that wrapping. I mentioned that the
      > >only benefit I could see was that if I screw up my setUp() and
      > >tearDown() methods and don't actually initialize and clean up the
      > >fixture correctly, the wrapping of method invocations may let me get
      > >away with it. Vladimir Bossicard agreed that that was a benefit, and no
      > >one else offered any others.
      > >
      > >My design sense when I was doing that part of SuiteRunner was to not
      > >provide the extra shield. I figured it would be relatively rare that a
      > >user would screw up their setUpFixture() and tearDownFixture() methods.
      > >When they do, they get a red bar and can fix the bug like any other
      > >bug. Then they get a green bar. And all the while the hierarchy of
      > >objects that make up their test is the intuitive simple tree of objects
      > >that for a long time (until I realized that the object wrapping was
      > >going on) I imagined JUnit was building.
      > >
      > >Bill
      > >
      > >
      > >
      > >>Bob
      > >>
      > >>
      > >>__________________________________________________
      > >>Do you Yahoo!?
      > >>Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!
      > >>http://platinum.yahoo.com
      > >>
      > >>
      > >>------------------------ Yahoo! Groups Sponsor
      > >>---------------------~-->
      > >>Get 128 Bit SSL Encryption!
      > >>http://us.click.yahoo.com/xaxhjB/hdqFAA/xGHJAA/5cFolB/TM
      > >>---------------------------------------------------------------------
      > >>~->
      > >>
      > >>To unsubscribe from this group, send an email to:
      > >>junit-unsubscribe@yahoogroups.com
      > >>
      > >>
      > >>Your use of Yahoo! Groups is subject to
      > >>http://docs.yahoo.com/info/terms/
      > >>
      > >>
      > >>
      > >>
      > >>
      > >>
      > >bv
      > >--
      > >Bill Venners
      > >Artima Software, Inc.
      > >http://www.artima.com
      > >
      > >
      > >
      > >
      > >To unsubscribe from this group, send an email to:
      > >junit-unsubscribe@yahoogroups.com
      > >
      > >
      > >Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
      > >
      > >
      > >
      > >
      >
      >
      >
      >
      > To unsubscribe from this group, send an email to:
      > junit-unsubscribe@yahoogroups.com
      >
      >
      > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
      >
      >


      __________________________________________________
      Do you Yahoo!?
      Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!
      http://platinum.yahoo.com
    • ravi_chaddha
      I fully agree with the solution that Levi has provided. This is 90% similar and bettr to what I implemented when I faced the same problem. -Ravi
      Message 2 of 27 , Mar 27, 2003
        I fully agree with the solution that Levi has provided. This is 90% similar and bettr to what I implemented when I faced the same problem.


        -Ravi

        junit@yahoogroups.com wrote:

        Once you've gone static, I could imagine this sort of hackery... (I don't endorse it though:)

        SomeTest extends TestCase
        {
        static Connection myConnection = null
        static int numTestsRun = 0

        protected void setUp()
        {
        if (myConnection == null)
        myConnection = createMyConnection()
        }

        public void testA(){}
        public void testB(){}
        public void testC(){}

        protected void tearDown()
        {
        numTestsRun++;
        if(numTestsRun == countTestCases())
        release(myConnection)
        }

        private Connection createMyConnection()
        {
        // do something "expensive"
        }

        private release(Connection theConnection)
        {
        // do the good citizen clean up thing...
        }
        }


        -- Levi



        Bill Venners wrote:

        >Bob,
        >
        >On Sunday, March 23, 2003, at 11:29 AM, Robert Bateman wrote:
        >
        >
        >
        >>--- Bill Venners <bv@...> wrote:
        >>
        >>
        >>>If the fixture includes an expensive database
        >>>connection, for example, could that connection not be created by the
        >>>first test method and stored in a static variable for all subsequent
        >>>test methods to share? Not sure how you could close the connection at
        >>>the end of the last test method executed, though. Has anyone used
        >>>static variables to share fixture objects among multiple test methods?
        >>>
        >>>
        >>I did this very thing by accident - as I'm new to JUnit testing.
        >>
        >>I have legacy DB code I have to test and the original author used a
        >>static anonymous class to
        >>create the connection cache. I use setup() to instantiate the
        >>underlying class and get/close my
        >>DB connections in each test. I pay the penalty for the connection
        >>creation in the first test, but
        >>every other test is fairly fast.
        >>
        >>
        >>So far, I've found JUnits testing of each test method to be low level
        >>in design and nature... I
        >>create a method in an object and my test methods exercise my method -
        >>checking for validity of
        >>execution. I've found JUnit assumes I'm interested in assuring the
        >>tested method executes and
        >>provides some specific result.
        >>
        >>Maybe I'm still too new to JUnit to know what I'm missing with
        >>SuiteRunner - but I've always
        >>thought the first test I must *always* perform is the validation of my
        >>code against the
        >>specifications - that what I'm writing is performing to expectations.
        >>
        >>Your right, if I write code that modifies a part of my object in some
        >>way, I need to insure that I
        >>haven't created an artifact that can damage some other part of the
        >>code. Isn't that the basis of
        >>performing lots of different asserts in each of your tests? If I can
        >>alter some part of my object
        >>thru my code, then after my code runs, don't I want to verify the
        >>contents of the underlying
        >>object? All within one test? (Not Suite of tests - but an individual
        >>test...)
        >>
        >>If I'm too far off topic, please forgive me.
        >>
        >>
        >>
        >Not off topic at all. I was asking if anyone had used static members to
        >share fixture among multiple test methods in a single TestCase, and you
        >did. You even did it for a database connection, which was the example I
        >mentioned. The one question I still have about your test code is, did
        >you find a way to explicitly close the connection after the last test
        >method finished? Or was it just left open under the assumption your app
        >would go away soon enough.
        >
        >One significant difference between the static member approach to
        >fixture sharing in JUnit and SuiteRunner is that I know how to close
        >the connection when I'm done in SuiteRunner, but not in JUnit. If
        >anyone has a way to do that, please reply.
        >
        >Another difference is really one of design taste I suspect. I just
        >found it non-intuitive that JUnit gave each test method invocation its
        >own instance, especially when they also provided the setUp() method. I
        >used JUnit a long time before I realized this object wrapping was going
        >on. In a previous post to this list, I asked if anyone could help me
        >understand what benefit I get for that wrapping. I mentioned that the
        >only benefit I could see was that if I screw up my setUp() and
        >tearDown() methods and don't actually initialize and clean up the
        >fixture correctly, the wrapping of method invocations may let me get
        >away with it. Vladimir Bossicard agreed that that was a benefit, and no
        >one else offered any others.
        >
        >My design sense when I was doing that part of SuiteRunner was to not
        >provide the extra shield. I figured it would be relatively rare that a
        >user would screw up their setUpFixture() and tearDownFixture() methods.
        >When they do, they get a red bar and can fix the bug like any other
        >bug. Then they get a green bar. And all the while the hierarchy of
        >objects that make up their test is the intuitive simple tree of objects
        >that for a long time (until I realized that the object wrapping was
        >going on) I imagined JUnit was building.
        >
        >Bill
        >
        >
        >
        >>Bob
        >>
        >>
        >>__________________________________________________
        >>Do you Yahoo!?
        >>Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!
        >>http://platinum.yahoo.com
        >>
        >>
        >>------------------------ Yahoo! Groups Sponsor
        >>---------------------~-->
        >>Get 128 Bit SSL Encryption!
        >>http://us.click.yahoo.com/xaxhjB/hdqFAA/xGHJAA/5cFolB/TM
        >>---------------------------------------------------------------------
        >>~->
        >>
        >>To unsubscribe from this group, send an email to:
        >>junit-unsubscribe@yahoogroups.com
        >>
        >>
        >>Your use of Yahoo! Groups is subject to
        >>http://docs.yahoo.com/info/terms/
        >>
        >>
        >>
        >>
        >>
        >>
        >bv
        >--
        >Bill Venners
        >Artima Software, Inc.
        >http://www.artima.com
        >
        >
        >
        >
        >To unsubscribe from this group, send an email to:
        >junit-unsubscribe@yahoogroups.com
        >
        >
        >Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
        >
        >
        >
        >







        Yahoo! Groups Sponsor





        ADVERTISEMENT



        To unsubscribe from this group, send an email to:
        junit-unsubscribe@yahoogroups.com


        Your use of Yahoo! Groups is subject to the Yahoo! Terms of Service.

        Get Your Private, Free E-mail from Indiatimes at http://email.indiatimes.com
        Buy The Best In BOOKS at http://www.bestsellers.indiatimes.com
        Bid for Air Tickets @ Re.1 on Air Sahara Flights. Just log on to http://airsahara.indiatimes.com and Bid Now !


        [Non-text portions of this message have been removed]
      • roger_k_white
        ... close ... I think the way to do this within the JUnit framework is to use the TestSuite to group tests. Looks something like this: public class DBTestCase
        Message 3 of 27 , Mar 28, 2003
          --- In junit@yahoogroups.com, Bill Venners <bv@a...> wrote:
          >
          > One significant difference between the static member approach to
          > fixture sharing in JUnit and SuiteRunner is that I know how to
          close
          > the connection when I'm done in SuiteRunner, but not in JUnit. If
          > anyone has a way to do that, please reply.

          I think the way to do this within the JUnit framework is to use the
          TestSuite to group tests. Looks something like this:

          public class DBTestCase extends TestCase {
          String connectString
          DB_Connection connection;

          DBTestCase(String name, String connectIn) {
          super(name);
          connectString = connectIn;
          }
          protected void setUp() {
          // open connection
          }
          protected void tearDown() {
          // close connection
          }
          protected void runTest(){
          // grab all public methods starting with "test"
          TestSuite allDBTests = new TestSuite(getClass());
          allDBTests.run();
          }
          }

          Then you add a bunch of testXXXX() methods. Better yet, you could
          extend DBTestCase, and just write all the testXXXX methods in the
          subclass--that way you can have different sets of db tests, and
          reuse the DBTestCase.


          > Another difference is really one of design taste I suspect. I
          just
          > found it non-intuitive that JUnit gave each test method invocation
          its
          > own instance, especially when they also provided the setUp()
          method.

          When you say JUnit gives each test method invocation it's own
          instance, I'm assuming you are refering to the default way
          TestCase.runTest() works (trying to run a method with the same name
          as the test case). I hardly ever use the default runTest()--my
          guess is that it is only left in there for backward-compatibility.

          I find the type of runTest() I showed above much more useful.
          Would this solution address the problems you were concerned with?
        • Bernd
          Bill, ... So, why does the text runner not use the class reloading? Does the swing runner use class-reloading only for that it can be used from within an
          Message 4 of 27 , Apr 1 11:44 AM
            Bill,

            > >> That's true, but I still have the question: What does running each
            > >> test method
            > >> in its own instance buy you that setUp and tearDown don't
            > already buy
            > >> you?
            > >> The only advantage I can see is that you can screw up your setUp
            > >> method by
            > >> forgetting to recreate something. Running each test method
            > in its own
            > >> instance shields you from any problem.
            > >
            > > e.g. static class members are not safely initialized if you share
            > > instances.
            > >
            > I'm not sure what you mean. Perhaps you could clarify? The static
            > variables will be initialized once when the class is first "actively"
            > used, not when each instance is created.

            You said exactly what I meant:

            > If you're using
            > JUnit's Swing
            > runner and reloading classes each time, the static members will be
            > initialized once per run.

            So, why does the text runner not use the class reloading?
            Does the swing runner use class-reloading "only" for that it can be
            used from within an IDE?

            Bernd
          • Bill Venners
            Bernd, ... I believe the text runner does in effect reload classes each time by exiting the app after each run. Each time you run with the text runner, you get
            Message 5 of 27 , Apr 1 1:10 PM
              Bernd,

              On Tuesday, April 1, 2003, at 11:44 AM, Bernd wrote:

              > Bill,
              >
              >>>> That's true, but I still have the question: What does running each
              >>>> test method
              >>>> in its own instance buy you that setUp and tearDown don't
              >> already buy
              >>>> you?
              >>>> The only advantage I can see is that you can screw up your setUp
              >>>> method by
              >>>> forgetting to recreate something. Running each test method
              >> in its own
              >>>> instance shields you from any problem.
              >>>
              >>> e.g. static class members are not safely initialized if you share
              >>> instances.
              >>>
              >> I'm not sure what you mean. Perhaps you could clarify? The static
              >> variables will be initialized once when the class is first "actively"
              >> used, not when each instance is created.
              >
              > You said exactly what I meant:
              >
              >> If you're using
              >> JUnit's Swing
              >> runner and reloading classes each time, the static members will be
              >> initialized once per run.
              >
              > So, why does the text runner not use the class reloading?
              > Does the swing runner use class-reloading "only" for that it can be
              > used from within an IDE?
              >
              I believe the text runner does in effect reload classes each time by
              exiting the app after each run. Each time you run with the text runner,
              you get a new VM, which reloads classes anew. I believe this is the
              case. It has been a while since I used the text runner.

              bv
              --
              Bill Venners
              Artima Software, Inc.
              http://www.artima.com
            • Levi Cook
              ... The code snippet I posted was pure speculation. That said, I expected the general idea to work. I ll try out a real test of this idea and post working
              Message 6 of 27 , Apr 1 4:52 PM
                On Wednesday, March 26, 2003, at 12:07 PM, Robert Bateman wrote:

                > I tried this - it doesn't work :(

                The code snippet I posted was pure speculation.

                That said, I expected the general idea to work. I'll try out a "real"
                test of this idea and post working code (or not) later.


                -- Levi

                [Non-text portions of this message have been removed]
              • Levi Cook
                ... Here s something less speculative... My tearDown method still needed some work. In particular TestCase.countTestCases() didn t do what I (incorrectly)
                Message 7 of 27 , Apr 1 6:52 PM
                  On Tuesday, April 1, 2003, at 06:52 PM, Levi Cook wrote:

                  >
                  > On Wednesday, March 26, 2003, at 12:07 PM, Robert Bateman wrote:
                  >
                  >> I tried this - it doesn't work :(
                  >
                  > The code snippet I posted was pure speculation.

                  Here's something less speculative...

                  My tearDown method still needed some work. In particular
                  "TestCase.countTestCases()" didn't do what I (incorrectly) thought it
                  should. I made a classic JUnit error and confused "TestCase" and
                  "Test". Anyway, I ended up writing a one off utility method
                  "countTestMethods()" that does what I expected & all was well...

                  For what its worth, this example still isn't recommended. Its
                  functional & could easily be improved, but it smells bad.

                  -- Levi


                  GoneStatic.java
                  ------------------------------------------------------------------------
                  ----------------------------------------------

                  import java.lang.reflect.Method;

                  import junit.framework.TestCase;
                  import junit.swingui.TestRunner;


                  public final class GoneStatic extends TestCase {

                  private static Connection myConnection = null;
                  private static int numTestsRun = 0;

                  protected void setUp() {
                  if (myConnection == null) {
                  myConnection = createMyConnection();
                  }
                  }

                  public void testA() {
                  }
                  public void testB() {
                  }
                  public void testC() {
                  }

                  protected void tearDown() {
                  numTestsRun++;

                  //if (numTestsRun == countTestCases()) {
                  // ^^^^^^^^^^^^^^
                  // oops, doesn't do what I expected, my bad
                  //
                  if (numTestsRun == countTestMethods()) {
                  myConnection.close();
                  myConnection = null;
                  numTestsRun = 0;
                  }
                  }

                  private Connection createMyConnection() {
                  // do something "expensive"
                  // (aka. sleep 10 seconds:)
                  return new Connection();
                  }

                  private int countTestMethods() {
                  int count = 0;

                  Method[] methods = getClass().getMethods();

                  for(int i = 0; i < methods.length; i++) {
                  if(methods[i].getName().startsWith("test")) {
                  count++;
                  }
                  }

                  return count;
                  }


                  public static void main(String[] args) {
                  TestRunner.run(GoneStatic.class);
                  }


                  private static class Connection {

                  private static Object lock = null;

                  private Connection() {
                  System.out.println("Entered Connection()");
                  printState();

                  if (lock != null) {
                  throw new UnsupportedOperationException("There can only be one!");
                  }
                  else {
                  lock = new Object();
                  }

                  try {
                  Thread.sleep(10000);
                  } catch (InterruptedException e) {
                  System.out.println("This isn't supposed to happen :(");
                  e.printStackTrace();
                  }
                  }

                  private void close() {
                  System.out.println("Entered Connection.close()");
                  printState();

                  if(lock == null) {
                  throw new UnsupportedOperationException("I'm already closed!");
                  }
                  else {
                  lock = null;
                  }
                  }

                  private void printState() {
                  System.out.print(this);
                  System.out.print(": lock=");
                  System.out.println(lock);
                  System.out.println("-----------");
                  }
                  }
                  }


                  > -- Levi


                  [Non-text portions of this message have been removed]
                • Eric Armstrong
                  ... Excellent observation. I had overlooked that.
                  Message 8 of 27 , Apr 10 8:25 PM
                    kathyvs wrote:
                    >
                    > For Strings and such, assertEquals(x, y) handles the case when x
                    > (or y) is null, which does not happen with verify(x.equals(y)).
                    >
                    Excellent observation. I had overlooked that.
                  Your message has been successfully submitted and would be delivered to recipients shortly.