Question re testing constructor

N

Novice

I'm writing JUnit test cases for a constructor but have hit a bit of a
snag. I hope someone here can help.

I've satisfied myself via googling that it makes sense to test constructors
if they do something that might fail or if they can throw exceptions. The
constructor in question can throw exceptions so I'm trying to write some
test cases for it. I've got cases that cause each of the exceptions to be
thrown but I'm having a bit of a problem with what seemed like the easiest
test of all: existence.

It seems to me - correct me if I'm wrong - that I can easily test to make
sure the constructor actually built SOMETHING by testing the object against
null. That won't prove it created exactly the right object but it will
prove that something got created. Testing the objects OTHER methods will
verify that the correct object got created.

If that is right, then it seems that this should test the existence of the
object well enough:

Set<String> testValues = new HashSet<String>();
testValues.add("FF0000");
testValues.add("66CC99");

for (String key : testValues) {
HexColor hexColor = new HexColor(key);
if (hexColor == null) {
assertTrue("The HexColor has been created for input value,
" + key + ", but has been found to be null.", false);
}
}

Unfortunately, the assertTrue() statement gets flagged by the compiler as
being dead code. Am I right in assuming that it is essentially looking at
the instantiation of the HexColor class and reasoning that it will
inevitably create SOMETHING so that hexColor can't possibly be null,
therefore the assertTrue() can't ever be executed?

If so, I don't have a problem with that but it leaves me a bit baffled
about how to test that the constructor created something when I gave it
good input values.

Can someone enlighten me on a better way to test this aspect of the
constructor? Or can I simply assume that the constructor worked as long as
it didn't actually throw an exception and omit any existence tests?
 
M

markspace

Unfortunately, the assertTrue() statement gets flagged by the compiler as
being dead code. Am I right in assuming that it is essentially looking at
the instantiation of the HexColor class and reasoning that it will
inevitably create SOMETHING so that hexColor can't possibly be null,
therefore the assertTrue() can't ever be executed?

I'm pretty sure, yes. The "new" operator always has to return an
object, or throw an error. Factory methods are just methods, and can
return null, but new *must* return an object if it completes.

P.S. Don't use assertTrue just to print something. Just use
System.out.println, it works fine, and makes your intent more clear.
 
N

Novice

[...]
I've satisfied myself via googling that it makes sense to test
constructors if they do something that might fail or if they can
throw exceptions. The constructor in question can throw exceptions so
I'm trying to write some test cases for it. I've got cases that cause
each of the exceptions to be thrown but I'm having a bit of a problem
with what seemed like the easiest test of all: existence.

It seems to me - correct me if I'm wrong - that I can easily test to
make sure the constructor actually built SOMETHING by testing the
object against null. [...]

Sorry. You're wrong. :) Simply executing the next statement
following the use of "new" is all the confirmation you need "to make
sure the constructor actually built SOMETHING". Testing against
"null" yields no additional information.

As "markspace" says, the "new" operator always returns a new object.
The only way for it to fail is to throw an exception, in which case
the "new" operator never actually returns per se (and so any code that
follows it is reachable only the case where it returns a non-null
value).

So you don't need to test for existence. Checking for a "null" return
value will needlessly verify that "new" succeeded, but cannot detect
failure because that's not how "new" reports a failure. Just test the
exceptions as you're already doing.

Thanks Pete! You and markspace have clarified things for me and saved me
some work to boot since I can now delete the existence tests.
 
N

Novice

markspace said:
I'm pretty sure, yes. The "new" operator always has to return an
object, or throw an error. Factory methods are just methods, and can
return null, but new *must* return an object if it completes.
Thanks Mark! Pete confirms your understanding in his reply to my question.
P.S. Don't use assertTrue just to print something. Just use
System.out.println, it works fine, and makes your intent more clear.

No problem. I'd just gotten into the habit of using assertTrue() in my
tests and didn't think through whether it was actually necessary in this
case.
 
D

Daniel Pitts

I'm writing JUnit test cases for a constructor but have hit a bit of a
snag. I hope someone here can help.

I've satisfied myself via googling that it makes sense to test constructors
if they do something that might fail or if they can throw exceptions. The
constructor in question can throw exceptions so I'm trying to write some
test cases for it. I've got cases that cause each of the exceptions to be
thrown but I'm having a bit of a problem with what seemed like the easiest
test of all: existence.

It seems to me - correct me if I'm wrong - that I can easily test to make
sure the constructor actually built SOMETHING by testing the object against
null. That won't prove it created exactly the right object but it will
prove that something got created. Testing the objects OTHER methods will
verify that the correct object got created.

If that is right, then it seems that this should test the existence of the
object well enough:

Set<String> testValues = new HashSet<String>();
testValues.add("FF0000");
testValues.add("66CC99");

for (String key : testValues) {
HexColor hexColor = new HexColor(key);
if (hexColor == null) {
assertTrue("The HexColor has been created for input value,
" + key + ", but has been found to be null.", false);
}
}

Unfortunately, the assertTrue() statement gets flagged by the compiler as
being dead code. Am I right in assuming that it is essentially looking at
the instantiation of the HexColor class and reasoning that it will
inevitably create SOMETHING so that hexColor can't possibly be null,
therefore the assertTrue() can't ever be executed?

If so, I don't have a problem with that but it leaves me a bit baffled
about how to test that the constructor created something when I gave it
good input values.

Can someone enlighten me on a better way to test this aspect of the
constructor? Or can I simply assume that the constructor worked as long as
it didn't actually throw an exception and omit any existence tests?

Tests work best if you think about pre-conditions and post-conditions.

Test 1:
Pre condition: I pass these objects to a constructor...
Expected post conditions: I have an object with these state/behavior.

Test 2:
Pre condition: I pass these other objects to a constructor...
Expected post condition: Constructor throws NullPointerException.


Etc...

So, if your constructor is non-trivial, you should be able to interact
with the object to verify the constructor did its job.
 
S

Stefan Ram

markspace said:
I'm pretty sure, yes.

If the Java compiler is so smart at detecting null values,
why does he not also give an error on code like:

(( java.io.PrintStream )null ).println()

?
 
T

Tom Anderson

P.S. Don't use assertTrue just to print something. Just use
System.out.println, it works fine, and makes your intent more clear.

What? No. He's not printing something, he's throwing an AssertionError.
He wrote:

assertTrue("The HexColor has been created for input value," + key + ", but has been found to be null.", false);

"assertTrue(s, false)" boils down to "throw new AssertionError(s)". With a
console-based JUnit runner, that will probably lead to something being
printed, but it's by no means the same thing as System.out.println. For
starters, one will lead to the test failing, and the other will not!

The standard idiom for this situation is:

Assert.fail("your message here");

That doesn't do anything more than throw an AssertionError, but it's the
conventional style.

I imagine you knew this, and were concentrating on the substantive matter
of the question. I hope you don't mind me pointing it out.

tom
 
I

Ian Shef

(e-mail address removed)-berlin.de (Stefan Ram) wrote in @ram.dialup.fu-berlin.de:
If the Java compiler is so smart at detecting null values,
why does he not also give an error on code like:

(( java.io.PrintStream )null ).println()

?
Short answer: Because the JLS says so. (see the third edition, paragraph
15.16 where it is explained that most casts are handled at run time).

Aside: If the method being called (e.g. println()) is static, this is ugly
but not an error.

Discussion: The JLS seems to treat casting separately from the operations
(such as calling a method) that would follow a cast. It "feels like" this
doesn't need to be the case. Thus I agree with Stefan that it "feels like"
the compiler or an IDE could catch this at compile time (Eclipse does not) if
the JLS permitted or required it. Perhaps someone can explain why this is
not the case.
 
R

Roedy Green

It seems to me - correct me if I'm wrong - that I can easily test to make
sure the constructor actually built SOMETHING by testing the object against
null.

The idea is to test YOUR code not Sun/Oracle's . Constructors never
produce null and never produce objects of the wrong type. Factories
might, but not constructors.

What you might want is an assert that makes sure you remembered to
init all necessary fields in the object.
--
Roedy Green Canadian Mind Products
http://mindprod.com
For me, the appeal of computer programming is that
even though I am quite a klutz,
I can still produce something, in a sense
perfect, because the computer gives me as many
chances as I please to get it right.
 
S

Stefan Ram

Ian Shef said:
(e-mail address removed)-berlin.de (Stefan Ram) wrote in @ram.dialup.fu-berlin.de:
Short answer: Because the JLS says so. (see the third edition, paragraph
15.16 where it is explained that most casts are handled at run time).

Something similar:

It is difficult for me to forecast an »unreachable statement« error.
For example, I would have expected such an error for

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( "alpha3" );
if( true )return;
java.lang.System.out.println( "beta3" ); }}

, but did *not* get one, however, the compiler knows that the
beta3 statement *is* unreachable, because he does not care to
compile it.

Omitting the »if( true )« will give an »unreachable statement«
error.
 
J

Joshua Cranmer

Ian Shef said:
(e-mail address removed)-berlin.de (Stefan Ram) wrote in @ram.dialup.fu-berlin.de:
Short answer: Because the JLS says so. (see the third edition, paragraph
15.16 where it is explained that most casts are handled at run time).

Something similar:

It is difficult for me to forecast an »unreachable statement« error.
For example, I would have expected such an error for

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( "alpha3" );
if( true )return;
java.lang.System.out.println( "beta3" ); }}

, but did *not* get one, however, the compiler knows that the
beta3 statement *is* unreachable, because he does not care to
compile it.

IIRC, the JLS actually describes why this case does not generate an
unreachable code exception. The idea is to permit what is, in essence,
conditional compilation:

class Foo {
public final static bool DEBUG = false;

public void frozinate() {
if (DEBUG)
log("Frozinating...");
// ... do real work ...
}
}

By handling this case, you could switch the value of DEBUG to select or
unselect some code to be run at runtime; you shouldn't have to eradicate
all if(DEBUG) code whenever you throw the switch to false.
 
H

Henk van Voorthuijsen

If that is right, then it seems that this should test the existence of the
object well enough:

        Set<String> testValues = new HashSet<String>();
        testValues.add("FF0000");
        testValues.add("66CC99");

        for (String key : testValues) {
                HexColor hexColor = new HexColor(key);
                if (hexColor == null) {
                        assertTrue("The HexColor has been created for input value,
" + key + ", but has been found to be null.", false);
                }
        }

To assert an objects existence, use assertNotNull().
 
L

Lew

Stefan said:
Something similar:

It is difficult for me to forecast an �unreachable statement� error.
For example, I would have expected such an error for

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( "alpha3" );
if( true )return;
java.lang.System.out.println( "beta3" ); }}

, but did *not* get one, however, the compiler knows that the
beta3 statement *is* unreachable, because he does not care to
compile it.

Omitting the �if( true )� will give an �unreachable statement�
error.

You should read the JLS, 14.21:
"The if statement, whether or not it has an else part, is handled in an unusual
manner. For this reason, it is discussed separately at the end of this section."
 
L

Lew

Ian said:
Discussion: The JLS seems to treat casting separately from the operations
(such as calling a method) that would follow a cast. It "feels like" this
doesn't need to be the case. Thus I agree with Stefan that it "feels like"
the compiler or an IDE could catch this at compile time (Eclipse does not) if
the JLS permitted or required it. Perhaps someone can explain why this is
not the case.

Short answer: Because despite its best efforts, the compiler cannot cure
stupidity.

The compiler likely sees this as not different from
'((PrintStream)variable).println()', i.e., as a candidate for a
'NullPointerException' rather than a compiler error.
 
I

Ian Shef

Short answer: Because despite its best efforts, the compiler cannot cure
stupidity.
Agreed.


The compiler likely sees this as not different from
'((PrintStream)variable).println()', i.e., as a candidate for a
'NullPointerException' rather than a compiler error.

That would seem to be the intent of the JLS. The compiler follows the rules
laid down by the JLS.

On the other hand, there are many places in the JLS where constants or
literals are treated specially, and where responsibility is shared between
the compiler and the JVM. Casts are not treated this way and are the
responsibility of the JVM (with some minor exceptions, such as when the
compiler can guarantee that a cast is unnecessary e.g., a widening reference
conversion).

My preference is to find such errors as early as possible. However, the
compiler can't save programmers from all folly. _Java Puzzlers_ by Joshua
Bloch and Neal Gafter has other examples where a cast is "obviously" an error
but it won't be caught until run time. [My copy of the book is currently 25
miles away, so I can't provide a more precise reference.]
 
I

Ian Shef

Short answer: Because despite its best efforts, the compiler cannot
cure stupidity.
Agreed.


The compiler likely sees this as not different from
'((PrintStream)variable).println()', i.e., as a candidate for a
'NullPointerException' rather than a compiler error.

That would seem to be the intent of the JLS. The compiler follows the
rules laid down by the JLS.

On the other hand, there are many places in the JLS where constants or
literals are treated specially, and where responsibility is shared
between the compiler and the JVM. Casts are not treated this way and
are the responsibility of the JVM (with some minor exceptions, such as
when the compiler can guarantee that a cast is unnecessary e.g., a
widening reference conversion).

My preference is to find such errors as early as possible. However, the
compiler can't save programmers from all folly. _Java Puzzlers_ by
Joshua Bloch and Neal Gafter has other examples where a cast is
"obviously" an error but it won't be caught until run time. [My copy
of the book is currently 25 miles away, so I can't provide a more
precise reference.]

I now have the book in my hands (5th Printing June 2008). The third
program in "Puzzle 50: Not Your Type" looks like this:

public class Type3 {
public static void main(String args[]) {
Type3 t3 = (Type3) new Object();
}
}

Any typos are mine, not the authors'.

SPOILER ALERT










This program compiles but fails at run time. The compiler (per the JLS)
requires that Object be a subtype of Type3, or vice versa.

The authors write "Although it is obvious to us that this cast will fail,
the type system is not powerful enough to know that the run-time type of
the expression new Object() cannot be a subtype of Type3. Therefore, the
program throws a ClassCastException at run time."

The first and second programs of this puzzle involve instanceof, which has
behavior which is closely related to that of the cast operator. Although
the programs are quite simple, the results are counterintuitive (but in
accordance with the JLS).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top