Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #37292 > unrolled thread

Testing the functionality of sub classes

Started byCecil Westerhof <Cecil@decebal.nl>
First post2017-08-19 19:40 +0200
Last post2017-08-20 01:22 +0200
Articles 20 on this page of 22 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-19 19:40 +0200
    Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-19 21:44 +0200
      Re: Testing the functionality of sub classes Eric Sosman <esosman@comcast-dot-net.invalid> - 2017-08-19 16:47 -0400
        Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 01:30 +0200
          Re: Testing the functionality of sub classes Andreas Leitgeb <avl@logic.at> - 2017-08-20 11:50 +0000
            Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 14:49 +0200
              Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 15:36 +0200
                Re: Testing the functionality of sub classes Arne Vajhøj <arne@vajhoej.dk> - 2017-08-20 09:46 -0400
                  Re: Testing the functionality of sub classes Andreas Leitgeb <avl@logic.at> - 2017-08-20 14:33 +0000
                    Re: Testing the functionality of sub classes Arne Vajhøj <arne@vajhoej.dk> - 2017-08-20 11:14 -0400
                  Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 16:35 +0200
                    Re: Testing the functionality of sub classes Arne Vajhøj <arne@vajhoej.dk> - 2017-08-20 11:17 -0400
                      Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 18:13 +0200
                        Re: Testing the functionality of sub classes Arne Vajhøj <arne@vajhoej.dk> - 2017-08-20 12:28 -0400
                          Re: Testing the functionality of sub classes Arne Vajhøj <arne@vajhoej.dk> - 2017-08-20 13:06 -0400
                          Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 19:07 +0200
              Re: Testing the functionality of sub classes Arne Vajhøj <arne@vajhoej.dk> - 2017-08-20 11:21 -0400
                Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 18:17 +0200
            Re: Testing the functionality of sub classes v_borchert@despammed.com (Volker Borchert) - 2017-08-21 19:53 +0000
      Re: Testing the functionality of sub classes v_borchert@despammed.com (Volker Borchert) - 2017-08-19 21:15 +0000
        Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 01:36 +0200
      Re: Testing the functionality of sub classes Cecil Westerhof <Cecil@decebal.nl> - 2017-08-20 01:22 +0200

Page 1 of 2  [1] 2  Next page →


#37292 — Testing the functionality of sub classes

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-19 19:40 +0200
SubjectTesting the functionality of sub classes
Message-ID<87fucnh2wu.fsf@munus.decebal.nl>
I have a class that is extended in several sub classes. Is there a way
to let the tests for the super class to be run on all sub classes?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [next] | [standalone]


#37297

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-19 21:44 +0200
Message-ID<87y3qffim5.fsf@munus.decebal.nl>
In reply to#37292
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Cecil Westerhof <Cecil@decebal.nl> writes:
>>I have a class that is extended in several sub classes. Is there a way
>>to let the tests for the super class to be run on all sub classes?
>
>   You are looking for all subclasses of a class.
>
>   Maybe you can create the JavaDoc and then evaluate
>   the »All Know Subclasses« clause of the documentation
>   of this class?
>
>   Another way to do it without JavaDoc:
>
>   I assume we have JARs with the class and the subclasses.
>
>   We can iterate all entries of a JAR file.

I should have been more clear.

For the test of the super class AbstractSQL, I have written a test
class SQLTest in which I implemented all the tests with the sub class
SQLite3. But there will be more. At the moment there are only two sub
classes (the other is SQLH2) and for two classes it is not to much
work. But I expect it to become a little more. So I would like to
write the test class so that all the tests are done for all the sub
classes.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37300

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2017-08-19 16:47 -0400
Message-ID<ona7tq$igi$1@dont-email.me>
In reply to#37297
On 8/19/2017 3:44 PM, Cecil Westerhof wrote:
> ram@zedat.fu-berlin.de (Stefan Ram) writes:
> 
>> Cecil Westerhof <Cecil@decebal.nl> writes:
>>> I have a class that is extended in several sub classes. Is there a way
>>> to let the tests for the super class to be run on all sub classes?
>>
>>    You are looking for all subclasses of a class.
>>
>>    Maybe you can create the JavaDoc and then evaluate
>>    the »All Know Subclasses« clause of the documentation
>>    of this class?
>>
>>    Another way to do it without JavaDoc:
>>
>>    I assume we have JARs with the class and the subclasses.
>>
>>    We can iterate all entries of a JAR file.
> 
> I should have been more clear.
> 
> For the test of the super class AbstractSQL, I have written a test
> class SQLTest in which I implemented all the tests with the sub class
> SQLite3. But there will be more. At the moment there are only two sub
> classes (the other is SQLH2) and for two classes it is not to much
> work. But I expect it to become a little more. So I would like to
> write the test class so that all the tests are done for all the sub
> classes.

     Much depends on the way the tests are written.  I confess I have
written few unit tests for abstract classes, but will offer a couple
thoughts anyhow -- take 'em or leave 'em, they may or may not be
worth what you're paying ...

     Thought #1: Since you can't instantiate an abstract class, the
only "in isolation" unit tests you can write must be for the static
methods, if there are any.  Testing those should be straightforward,
and isn't something you need to repeat for subclasses.

     Thought #2: To test the instance methods provided by the abstract
class, you need one or more concrete subclasses.  Instead of using a
"real" subclass (as you seem to be doing now), you might be better
off writing purpose-built subclasses whose only role is to exercise
the superclass' constructors and instance methods.  Note that such a
subclass need not be a complete implementation of everything that
would go into a "real" class, but can be a skeletal implementation
that provides only enough for its own particular test.  For example,
to test that your superclass constructor validates arguments as it
should and throws the right exceptions when they're wrong, all you
need is a subclass that invokes the constructor in several different
ways, some correct and some erroneous.

     Thought #3: Once testing has made you confident of the abstract
superclass, you need not re-test the superclass methods for every
"real" subclass.  Just write subclass-specific tests for the features
that are unique to the subclass.

     Thought #4: If the tests for #3 become repetitive, perhaps you
can write many of them to accept an instance of the subclass and
run tests on it (or maybe an instance factory, if the tests need
several instances):

	class CommonTests {
	    public static void runTest(Superclass instance) {
	        // ... test the subclass in its Superclass guise
	    }
	}

	class Subclass1Tests {
	    public static void runTests() {
	        CommonTests.runTest(new Subclass1());
	        // ... Subclass1-specific tests ...
	    }
	}

	class Subclass2Tests {
	    public static void runTests() {
	        CommonTests.runTest(new Subclass2(true));
	        CommonTests.runTest(new Subclass2(false));
	        // ... Subclass2-specific tests ...
	    }
	}

     Thought #5: If the tests for #4 turn out to have a lot of stuff
in the subclass-specific portions, ponder whether the abstract
superclass truly adds much value to the overall design.

-- 
esosman@comcast-dot-net.invalid
Twelve hundred fifty days to go.

[toc] | [prev] | [next] | [standalone]


#37305

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 01:30 +0200
Message-ID<87pobrf855.fsf@munus.decebal.nl>
In reply to#37300
Eric Sosman <esosman@comcast-dot-net.invalid> writes:

>     Thought #3: Once testing has made you confident of the abstract
> superclass, you need not re-test the superclass methods for every
> "real" subclass.  Just write subclass-specific tests for the features
> that are unique to the subclass.

My sub classes use different JDBC drivers. I think I should test them
all, because if one does not implement something correctly I would not
find this.

For example: when creating a new ResultSet through a Statement the
previous generated should be closed. With the JDBC driver I use for
SQLite3 the old ResultSet is not closed, but becomes a copy from the
last generated.


-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37312

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-20 11:50 +0000
Message-ID<slrnopiu4a.o2q.avl@logic.at>
In reply to#37305
Cecil Westerhof <Cecil@decebal.nl> wrote:
> For example: when creating a new ResultSet through a Statement the
> previous generated should be closed. With the JDBC driver I use for
> SQLite3 the old ResultSet is not closed, but becomes a copy from the
> last generated.

Are you sure about the "copy"? I'd rather expect(*) that the driver 
re-uses the particular ResultSet instance and returns the same ref
again.  (*: that is: based on your posted observations. Usually, 
instance re-use is frowned upon, like premature optimisation, but then
again, DB driver vendors might have optimised it "well-maturely".)

To verify (or disprove) it, you could run it in e.g. eclipse, and see
if the same (or a new) "id" appears when you execute another query on
the same Statement.

Even without a debugger, you could print out the System.identityHashCode 
for the "two" returned ResultSet references.

[toc] | [prev] | [next] | [standalone]


#37313

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 14:49 +0200
Message-ID<87ziaue74o.fsf@munus.decebal.nl>
In reply to#37312
Andreas Leitgeb <avl@logic.at> writes:

> Cecil Westerhof <Cecil@decebal.nl> wrote:
>> For example: when creating a new ResultSet through a Statement the
>> previous generated should be closed. With the JDBC driver I use for
>> SQLite3 the old ResultSet is not closed, but becomes a copy from the
>> last generated.
>
> Are you sure about the "copy"? I'd rather expect(*) that the driver 
> re-uses the particular ResultSet instance and returns the same ref
> again.  (*: that is: based on your posted observations. Usually, 
> instance re-use is frowned upon, like premature optimisation, but then
> again, DB driver vendors might have optimised it "well-maturely".)

I am not sure: that is also possible. But what is important is that
the old ResultSet did not get closed. So if I run the test for the
super class with for example MySSQL and this closes the ResultSet (I
do not know, but lets pretend) and I do not also test with SQLite3 I
will not find this bug.


> To verify (or disprove) it, you could run it in e.g. eclipse, and see
> if the same (or a new) "id" appears when you execute another query on
> the same Statement.
>
> Even without a debugger, you could print out the System.identityHashCode 
> for the "two" returned ResultSet references.

Just to satisfy my curiosity I executed (I do not like the formatting,
but that is what Eclipse does):
    try (
            Statement stmt = conn.createStatement();
            ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
            ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
            ) {
        System.out.println(stmt);
        System.out.println(rsOne);
        System.out.println(rsTwo);
    }

And this gives:
    org.sqlite.jdbc4.JDBC4Statement@685f4c2e
    org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
    org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc

So yes, it is like you said: the ResultSet is reused. Is also more
logical. I jumped to a conclusion.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37314

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 15:36 +0200
Message-ID<87valie4xz.fsf@munus.decebal.nl>
In reply to#37313
Cecil Westerhof <Cecil@decebal.nl> writes:

> Just to satisfy my curiosity I executed (I do not like the formatting,
> but that is what Eclipse does):
>     try (
>             Statement stmt = conn.createStatement();
>             ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>             ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>             ) {
>         System.out.println(stmt);
>         System.out.println(rsOne);
>         System.out.println(rsTwo);
>     }
>
> And this gives:
>     org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>     org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>     org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>
> So yes, it is like you said: the ResultSet is reused. Is also more
> logical. I jumped to a conclusion.

With a H2 database I get:
    stat0
    rs0: null
    rs1: org.h2.result.LocalResult@1bc6a36e columns: 1 rows: 1 pos: -1

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37315

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-20 09:46 -0400
Message-ID<onc3s5$1ns5$1@gioia.aioe.org>
In reply to#37314
On 8/20/2017 9:36 AM, Cecil Westerhof wrote:
> Cecil Westerhof <Cecil@decebal.nl> writes:
>> Just to satisfy my curiosity I executed (I do not like the formatting,
>> but that is what Eclipse does):
>>      try (
>>              Statement stmt = conn.createStatement();
>>              ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>>              ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>>              ) {
>>          System.out.println(stmt);
>>          System.out.println(rsOne);
>>          System.out.println(rsTwo);
>>      }
>>
>> And this gives:
>>      org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>
>> So yes, it is like you said: the ResultSet is reused. Is also more
>> logical. I jumped to a conclusion.
> 
> With a H2 database I get:
>      stat0
>      rs0: null
>      rs1: org.h2.result.LocalResult@1bc6a36e columns: 1 rows: 1 pos: -1

That is what happens when you try and do unsupported things: you get
undefined/implementation specific behavior. Bad!

Arne

[toc] | [prev] | [next] | [standalone]


#37316

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-20 14:33 +0000
Message-ID<slrnopj7la.o2q.avl@logic.at>
In reply to#37315
Arne Vajhøj <arne@vajhoej.dk> wrote:
> On 8/20/2017 9:36 AM, Cecil Westerhof wrote:
>> Cecil Westerhof <Cecil@decebal.nl> writes:
>>> Just to satisfy my curiosity I executed (I do not like the formatting,
>>> but that is what Eclipse does):
>>>      try (
>>>              Statement stmt = conn.createStatement();
>>>              ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>>>              ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>>>              ) {
>>>          System.out.println(stmt);
>>>          System.out.println(rsOne);
>>>          System.out.println(rsTwo);
>>>      }
>>>
>>> And this gives:
>>>      org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>
>>> So yes, it is like you said: the ResultSet is reused. Is also more
>>> logical. I jumped to a conclusion.
>> 
>> With a H2 database I get:
>>      stat0
>>      rs0: null
>>      rs1: org.h2.result.LocalResult@1bc6a36e columns: 1 rows: 1 pos: -1
>
> That is what happens when you try and do unsupported things: you get
> undefined/implementation specific behavior. Bad!

In this particular case the "undefined/implementation specific behavior"
is ResultSet-implementation's toString().  That's why I suggested to use
System.identityHashCode().

[toc] | [prev] | [next] | [standalone]


#37318

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-20 11:14 -0400
Message-ID<onc90h$1vgf$1@gioia.aioe.org>
In reply to#37316
On 8/20/2017 10:33 AM, Andreas Leitgeb wrote:
> Arne Vajhøj <arne@vajhoej.dk> wrote:
>> On 8/20/2017 9:36 AM, Cecil Westerhof wrote:
>>> Cecil Westerhof <Cecil@decebal.nl> writes:
>>>> Just to satisfy my curiosity I executed (I do not like the formatting,
>>>> but that is what Eclipse does):
>>>>       try (
>>>>               Statement stmt = conn.createStatement();
>>>>               ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>>>>               ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>>>>               ) {
>>>>           System.out.println(stmt);
>>>>           System.out.println(rsOne);
>>>>           System.out.println(rsTwo);
>>>>       }
>>>>
>>>> And this gives:
>>>>       org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>>>>       org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>>       org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>>
>>>> So yes, it is like you said: the ResultSet is reused. Is also more
>>>> logical. I jumped to a conclusion.
>>>
>>> With a H2 database I get:
>>>       stat0
>>>       rs0: null
>>>       rs1: org.h2.result.LocalResult@1bc6a36e columns: 1 rows: 1 pos: -1
>>
>> That is what happens when you try and do unsupported things: you get
>> undefined/implementation specific behavior. Bad!
> 
> In this particular case the "undefined/implementation specific behavior"
> is ResultSet-implementation's toString().  That's why I suggested to use
> System.identityHashCode().

It is more than that. SQLite reuse result set object - H2 does not.

Arne

[toc] | [prev] | [next] | [standalone]


#37317

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 16:35 +0200
Message-ID<87o9rae27u.fsf@munus.decebal.nl>
In reply to#37315
Arne Vajhøj <arne@vajhoej.dk> writes:

> On 8/20/2017 9:36 AM, Cecil Westerhof wrote:
>> Cecil Westerhof <Cecil@decebal.nl> writes:
>>> Just to satisfy my curiosity I executed (I do not like the formatting,
>>> but that is what Eclipse does):
>>>      try (
>>>              Statement stmt = conn.createStatement();
>>>              ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>>>              ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>>>              ) {
>>>          System.out.println(stmt);
>>>          System.out.println(rsOne);
>>>          System.out.println(rsTwo);
>>>      }
>>>
>>> And this gives:
>>>      org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>
>>> So yes, it is like you said: the ResultSet is reused. Is also more
>>> logical. I jumped to a conclusion.
>>
>> With a H2 database I get:
>>      stat0
>>      rs0: null
>>      rs1: org.h2.result.LocalResult@1bc6a36e columns: 1 rows: 1 pos: -1
>
> That is what happens when you try and do unsupported things: you get
> undefined/implementation specific behavior. Bad!

Nope, it shows that the H2 driver does follow the standards (and the
SQLite3 driver does not). The first ResultSet is closed as it should
be. You can do an isClosed on it. So it is not null, but displays a
null to show you should not use it anymore.

I now defined also:
    case "--twoResultSetsOnStatement":
        if (parameters.length != 0) {
            break;
        }
        try (
                Statement stmt  = conn.createStatement();
                ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
                ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
                ) {
            System.out.println(stmt);
            System.out.println(rsOne);
            System.out.println(rsTwo);
            if (!rsOne.isClosed()) {
                System.out.println("ERROR: First ResultSet is not closed.");
            }
            if (rsOne == rsTwo) {
                System.out.println("ERROR: Statement reuses ResultSet.");
            }
        }
        return true;

So it is easy to check if a database driver confirms to this part of
the standard.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37319

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-20 11:17 -0400
Message-ID<onc96e$1vqj$1@gioia.aioe.org>
In reply to#37317
On 8/20/2017 10:35 AM, Cecil Westerhof wrote:
> Arne Vajhøj <arne@vajhoej.dk> writes:
> 
>> On 8/20/2017 9:36 AM, Cecil Westerhof wrote:
>>> Cecil Westerhof <Cecil@decebal.nl> writes:
>>>> Just to satisfy my curiosity I executed (I do not like the formatting,
>>>> but that is what Eclipse does):
>>>>       try (
>>>>               Statement stmt = conn.createStatement();
>>>>               ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>>>>               ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>>>>               ) {
>>>>           System.out.println(stmt);
>>>>           System.out.println(rsOne);
>>>>           System.out.println(rsTwo);
>>>>       }
>>>>
>>>> And this gives:
>>>>       org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>>>>       org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>>       org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>>>
>>>> So yes, it is like you said: the ResultSet is reused. Is also more
>>>> logical. I jumped to a conclusion.
>>>
>>> With a H2 database I get:
>>>       stat0
>>>       rs0: null
>>>       rs1: org.h2.result.LocalResult@1bc6a36e columns: 1 rows: 1 pos: -1
>>
>> That is what happens when you try and do unsupported things: you get
>> undefined/implementation specific behavior. Bad!
> 
> Nope, it shows that the H2 driver does follow the standards (and the
> SQLite3 driver does not). The first ResultSet is closed as it should
> be. You can do an isClosed on it. So it is not null, but displays a
> null to show you should not use it anymore.

The contract for toString is extremely vague.

I do not see any indication than SQLite does not follow
JDBC standard.

Reusing result set object should be perfectly valid
per JDBC standard.

And toString can practically return anything.

Arne

[toc] | [prev] | [next] | [standalone]


#37321

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 18:13 +0200
Message-ID<87h8x2dxp1.fsf@munus.decebal.nl>
In reply to#37319
Arne Vajhøj <arne@vajhoej.dk> writes:

>> Nope, it shows that the H2 driver does follow the standards (and the
>> SQLite3 driver does not). The first ResultSet is closed as it should
>> be. You can do an isClosed on it. So it is not null, but displays a
>> null to show you should not use it anymore.
>
> The contract for toString is extremely vague.
>
> I do not see any indication than SQLite does not follow
> JDBC standard.
>
> Reusing result set object should be perfectly valid
> per JDBC standard.

In the description of Statement (copied with spelling mistakes):
    All execution methods in the Statement interface implicitly close
    a statment's current ResultSet object if an open one exists.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37322

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-20 12:28 -0400
Message-ID<oncdbs$70j$1@gioia.aioe.org>
In reply to#37321
On 8/20/2017 12:13 PM, Cecil Westerhof wrote:
> Arne Vajhøj <arne@vajhoej.dk> writes:
>>> Nope, it shows that the H2 driver does follow the standards (and the
>>> SQLite3 driver does not). The first ResultSet is closed as it should
>>> be. You can do an isClosed on it. So it is not null, but displays a
>>> null to show you should not use it anymore.
>>
>> The contract for toString is extremely vague.
>>
>> I do not see any indication than SQLite does not follow
>> JDBC standard.
>>
>> Reusing result set object should be perfectly valid
>> per JDBC standard.
> 
> In the description of Statement (copied with spelling mistakes):
>      All execution methods in the Statement interface implicitly close
>      a statment's current ResultSet object if an open one exists.

It is exactly because of this that I think reuse is valid.

Arne

[toc] | [prev] | [next] | [standalone]


#37325

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-20 13:06 -0400
Message-ID<oncfj5$b69$1@gioia.aioe.org>
In reply to#37322
On 8/20/2017 12:28 PM, Arne Vajhøj wrote:
> On 8/20/2017 12:13 PM, Cecil Westerhof wrote:
>> Arne Vajhøj <arne@vajhoej.dk> writes:
>>>> Nope, it shows that the H2 driver does follow the standards (and the
>>>> SQLite3 driver does not). The first ResultSet is closed as it should
>>>> be. You can do an isClosed on it. So it is not null, but displays a
>>>> null to show you should not use it anymore.
>>>
>>> The contract for toString is extremely vague.
>>>
>>> I do not see any indication than SQLite does not follow
>>> JDBC standard.
>>>
>>> Reusing result set object should be perfectly valid
>>> per JDBC standard.
>>
>> In the description of Statement (copied with spelling mistakes):
>>      All execution methods in the Statement interface implicitly close
>>      a statment's current ResultSet object if an open one exists.
> 
> It is exactly because of this that I think reuse is valid.

Maybe I am just babbling.

But let me try and show what I am thinking about.

The code is far from complete, but it should hopefully
illustrate what I am thinking about.

public class OpenCloseFun {
	public static interface Connection extends AutoCloseable {
		public Statement createStatement();
	}
	public static interface Statement extends AutoCloseable {
		public ResultSet executeQuery(String sql);
	}
	public static interface ResultSet extends AutoCloseable {
		public boolean next();
	}
	public static class MyConnection implements Connection {
		private MyRealConnection real;
		private MyConnection(MyRealConnection real) {
			this.real = real;
		}
		public static MyConnection create() {
			return new MyConnection(new MyRealConnection());
		}
		public Statement createStatement() {
			return new MyStatement(real.createStatement());
		}
		public void close() throws Exception {
			real.close();
		}
		public String toString() {
			return real.toString();
		}
	}
	public static class MyStatement implements Statement {
		private MyRealStatement real;
		public MyStatement(MyRealStatement real) {
			this.real = real;
		}
		public ResultSet executeQuery(String sql) {
			return new MyResultSet(real.executeQuery(sql));
		}
		public void close() throws Exception {
			real.close();
		}
		public String toString() {
			return real.toString();
		}
	}
	public static class MyResultSet implements ResultSet {
		private MyRealResultSet real;
		public MyResultSet(MyRealResultSet real) {
			this.real = real;
		}
		public boolean next() {
			return real.next();
		}
		public void close() throws Exception {
			real.close();
		}
		public String toString() {
			return real.toString();
		}
	}
	public static class MyRealConnection implements Connection {
		private MyRealStatement stmt = new MyRealStatement(); // only one 
concurrent active Statement per Connection
		public MyRealStatement createStatement() {
			stmt.init();
			return stmt;
		}
		public void close() throws Exception {
			stmt.close();
		}
	}
	public static class MyRealStatement implements Statement {
		private MyRealResultSet rs = new MyRealResultSet(); // only one 
concurrent active ResultSet per Statement
		public void init() {
		}
		public MyRealResultSet executeQuery(String sql) {
			rs.init(sql);
			return rs;
		}
		public void close() throws Exception {
			rs.close();
		}
	}
	public static class MyRealResultSet implements ResultSet {
		public void init(String sql) {
		}
		public boolean next() {
			return true;
		}
		public void close() throws Exception {
		}
	}
	public static void main(String[] args) throws Exception {
		try(Connection con = MyConnection.create()) {
			try(Statement stmt = con.createStatement();
			    ResultSet rs1 = stmt.executeQuery("something");
				ResultSet rs2 = stmt.executeQuery("something else")) {
				System.out.println(stmt);
				System.out.println(rs1);
				System.out.println(rs2);
			}
		}
	}
}

Arne

[toc] | [prev] | [next] | [standalone]


#37327

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 19:07 +0200
Message-ID<878tiedv68.fsf@munus.decebal.nl>
In reply to#37322
Arne Vajhøj <arne@vajhoej.dk> writes:

> On 8/20/2017 12:13 PM, Cecil Westerhof wrote:
>> Arne Vajhøj <arne@vajhoej.dk> writes:
>>>> Nope, it shows that the H2 driver does follow the standards (and the
>>>> SQLite3 driver does not). The first ResultSet is closed as it should
>>>> be. You can do an isClosed on it. So it is not null, but displays a
>>>> null to show you should not use it anymore.
>>>
>>> The contract for toString is extremely vague.
>>>
>>> I do not see any indication than SQLite does not follow
>>> JDBC standard.
>>>
>>> Reusing result set object should be perfectly valid
>>> per JDBC standard.
>>
>> In the description of Statement (copied with spelling mistakes):
>>      All execution methods in the Statement interface implicitly close
>>      a statment's current ResultSet object if an open one exists.
>
> It is exactly because of this that I think reuse is valid.

I did not read it like that, but I suppose you could.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37320

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-20 11:21 -0400
Message-ID<onc9ed$e1$1@gioia.aioe.org>
In reply to#37313
On 8/20/2017 8:49 AM, Cecil Westerhof wrote:
> Just to satisfy my curiosity I executed (I do not like the formatting,
> but that is what Eclipse does):
>      try (
>              Statement stmt = conn.createStatement();
>              ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>              ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>              ) {
>          System.out.println(stmt);
>          System.out.println(rsOne);
>          System.out.println(rsTwo);
>      }
> 
> And this gives:
>      org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
> 
> So yes, it is like you said: the ResultSet is reused. Is also more
> logical. I jumped to a conclusion.

As soon as the second executeQuery is running then whatever rsOne
is pointing to is supposed to be toast.

So SQLite JDBC driver apparently decide to reuse the object for
the second executeQuery.

Maybe unexpected, but I believe it is OK per spec.

Arne

[toc] | [prev] | [next] | [standalone]


#37323

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-20 18:17 +0200
Message-ID<87d17qdxj5.fsf@munus.decebal.nl>
In reply to#37320
Arne Vajhøj <arne@vajhoej.dk> writes:

> On 8/20/2017 8:49 AM, Cecil Westerhof wrote:
>> Just to satisfy my curiosity I executed (I do not like the formatting,
>> but that is what Eclipse does):
>>      try (
>>              Statement stmt = conn.createStatement();
>>              ResultSet rsOne = stmt.executeQuery("SELECT 12 AS twelve");
>>              ResultSet rsTwo = stmt.executeQuery("SELECT 'Hello World!' AS message")
>>              ) {
>>          System.out.println(stmt);
>>          System.out.println(rsOne);
>>          System.out.println(rsTwo);
>>      }
>>
>> And this gives:
>>      org.sqlite.jdbc4.JDBC4Statement@685f4c2e
>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>      org.sqlite.jdbc4.JDBC4ResultSet@7daf6ecc
>>
>> So yes, it is like you said: the ResultSet is reused. Is also more
>> logical. I jumped to a conclusion.
>
> As soon as the second executeQuery is running then whatever rsOne
> is pointing to is supposed to be toast.
>
> So SQLite JDBC driver apparently decide to reuse the object for
> the second executeQuery.
>
> Maybe unexpected, but I believe it is OK per spec.

In the description of Statement (copied with spelling mistakes):
    All execution methods in the Statement interface implicitly close
    a statment's current ResultSet object if an open one exists.

Well, maybe you could say it is OK to reuse the old one, but it
certainly does surprise me.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37329

Fromv_borchert@despammed.com (Volker Borchert)
Date2017-08-21 19:53 +0000
Message-ID<onfdmu$gon$2@Gaia.teknon.de>
In reply to#37312
Andreas Leitgeb wrote:
> Cecil Westerhof <Cecil@decebal.nl> wrote:
> > For example: when creating a new ResultSet through a Statement the
> > previous generated should be closed. With the JDBC driver I use for
> > SQLite3 the old ResultSet is not closed, but becomes a copy from the
> > last generated.
> 
> Are you sure about the "copy"? I'd rather expect(*) that the driver 
> re-uses the particular ResultSet instance and returns the same ref
> again.  (*: that is: based on your posted observations. Usually, 
> instance re-use is frowned upon, like premature optimisation, but then
> again, DB driver vendors might have optimised it "well-maturely".)

With Oracle's thin driver, a client's ResultSet corresponds to a
server's cursor...

> To verify (or disprove) it, you could run it in e.g. eclipse,

jvisualvm should do, and comes with the JDK.

> and see
> if the same (or a new) "id" appears when you execute another query on
> the same Statement.

-- 

"I'm a doctor, not a mechanic." Dr Leonard McCoy <mccoy@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert  <v_borchert@despammed.com>

[toc] | [prev] | [next] | [standalone]


#37302

Fromv_borchert@despammed.com (Volker Borchert)
Date2017-08-19 21:15 +0000
Message-ID<ona9pc$5i6$1@Gaia.teknon.de>
In reply to#37297
Cecil Westerhof wrote:

> >>I have a class that is extended in several sub classes. Is there a way
> >>to let the tests for the super class to be run on all sub classes?
> >
> 
> For the test of the super class AbstractSQL, I have written a test
> class SQLTest in which I implemented all the tests with the sub class
> SQLite3. But there will be more. At the moment there are only two sub
> classes (the other is SQLH2) and for two classes it is not to much
> work. But I expect it to become a little more. So I would like to
> write the test class so that all the tests are done for all the sub
> classes.

Are you talking JUnit? Then have an abstract class annotated as
@RunWith(Suite.class) and @Suite.SuiteClasses({ <class literals
for all your concrete test classes> }) , containing most @Test
methods and declaring a single abstract method that provides
the concrete implementation object to test. For each concrete
class-to-test, you'll need a concrete test class deriving from
the above, listed in its @Suite.SuiteClasses, and implementing
the single abstract method. This derived test class may contain
additional @Test methods applicable to only this concrete
class-to-test.

<opinion>
This approach is not fullyautomagic, but simple enough to write
and, more important, easy enough to understand for the innocent
reader. Any tricks with javadoc parsing or JAR enumeration are
too brittle, too obfuscated, and too difficult to justify the
minimal savings of avoiding those derived test classes.
</opinion>

-- 

"I'm a doctor, not a mechanic." Dr Leonard McCoy <mccoy@ncc1701.starfleet.fed>
"I'm a mechanic, not a doctor." Volker Borchert  <v_borchert@despammed.com>

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.java.programmer


csiph-web