From: Eric Sosman on
On 5/20/2010 4:47 PM, Rhino wrote:
> Eric Sosman<esosman(a)ieee-dot-org.invalid> wrote:
>> [...]
>> For constructors, what you want to test is that they throw
>> exceptions when they're supposed to (e.g., InvalidArgumentException),
>> and that the newly-constructed object satisfies all the invariants
>> it's supposed to. In your no-argument Foo() constructor exceptions
>> seem unlikely (possible, though: think HeadlessException), but you
>> might check `myFoo.getHeight() * myFoo.getWidth() == myFoo.getArea()'
>> or whatever.
>>
> Could you expand on this last paragraph a bit. The part about verifying
> that exceptions get thrown at the appropriate time are fine but I'm not
> clear on what you mean by the invariants that it is supposed to satisfy.
> The last sentence is almost not quite clear. Are you saying to find some
> aspect of the work that is done in the constructor and verify that it
> took place, so that if it is drawing a GUI component, that the component
> exists and has dimensions greater that 0 x 0? What if the constructor
> does very very little - maybe just a super() - or even nothing at all? In
> those cases, is it sufficient to just do

Read the Javadoc for your Foo class, and consider what
properties a newly-constructed Foo instance should satisfy.
Test that they are satisfied -- that is, test that a newly-
constructed Foo complies with its "contract."

> if (Foo == null) fail("Constructor failed to instantiate the class");

Rhino, if you keep on spewing this sort of codecrap I'm going
to shove that horn of yours firmly up the orifice that spews.

>> You should test that the factory method behaves as advertised.
>> If it can return null under some circumstances, you should check that
>> it does so when it's supposed to and does not when it isn't. If it
>> returns non-null, the thing returned will necessarily be of the type
>> declared for the factory method -- but not necessarily of that "exact"
>> type, as it might be a subclass or any arbitrary implementation of an
>> interface type. That may make a difference in what you test.
>>
> Can you elaborate on this a bit? Can you show me a simple example of a
> constructor returning a subclass or implementation of an interface?

No, because a constructor cannot do such a thing. But you seemed
to be talking about a factory method (although it's hard to be sure
from reading your codecrap), and a factory method -- any method, in
fact -- can return anything compatible with its declared type. Wasn't
it you who had the problem with SpinnerNumberModel recently, where the
getNumber() method sometimes returned a Short, sometimes a Long,
sometimes something else?

>> I'd say it's unnecessary to test wait() and notify() and other
>> final methods of Object. More generally, it's probably unnecessary
>> to test final methods of any superclass.
>>
>> But equals() is not final, and if the class being tested has its
>> own equals() you should test it. (Note that it's extremely rare to
>> inherit equals() from a superclass unless you're inheriting it all
>> the way from Object undisturbed.) If you were writing tests for
>> Integer, you might test `new Integer(42).equals(new Integer("42"))',
>> for example, and `! new Integer(42).equals(new Integer("-42"))'.
>
> So, in a nutshell, only test the methods of the parent classes if I
> overrode them; otherwise, don't worry about them. That makes sense to me!

There's a subtle point there, a conflict between "black box"
and "clear box" testing. The only way you can *know* that a subclass
inherits a non-final method rather than overriding it is to peek
into the subclass' implementation (either by looking at the source
or by using reflection). But what if somebody comes along next week
and decides to override a method you decided not to test, on the
grounds that it was not overridden?

One thing you might do is run some of Super's unit tests on Sub
instances. Another might be to include a "sanity check" test in your
Sub, something that reflects on Sub and verifies that the methods
you've chosen not to test are in fact inherited.

Finally, you've got to realize that unit testing, important as it
is, is not the be-all and end-all of verifying correctness.

--
Eric Sosman
esosman(a)ieee-dot-org.invalid
From: Jim Janney on
Rhino <no.offline.contact.please(a)example.com> writes:

> I'm getting more and more comfortable with JUnit after a long absence
> from it but I'm still struggling with composing tests for some
> situations. If anyone can help with any of these situations, I'd love to
> hear your suggestions.
>
> --------------------------------
>
> Scenario 1 - Moving Targets
>
> What is the best way to test a method whose output is unpredictable
> because that output is a moving target? For example, I have a method that
> uses Locale.getAvailableLocales() to display all of the Locales on the
> current JVM. It works fine but how do I write a JUnit test, given that an
> upgrade to the JVM could introduce additional Locales? I'd have the same
> kind of problem if a method was returning a list of area codes or cell
> phone providers. There must be some standard way of writing a JUnit test
> for that but I'm drawing a blank.

Strictly speaking, unit testing means testing small bits of code in
isolation -- you break a program down into the smallest pieces that
can be tested independently (in Java this generally means a class) and
verify that each one satisfies its public contract. The public
contract is whatever it is that says how the class is supposed to
behave. In some languages (Eiffel and, um, uh, ...) this can be
formally specified in the language itself but more usually it's some
written description or just an idea in the programmer's mind. In Java
it may be in the Javadoc (the JRE classes are pretty good about this).

For example, the Javadoc for Locale.getAvailableLocales() specifies
that the result must contain Locale.US, so you could sensibly test for
this in a unit test. If your application depends on the presence of
other locales you may want to test for those also. Once you move past
this you're no longer doing unit testing but some sort of integration
testing. This is also valuable but the rules are different so it's
useful to remember which kind of testing you're doing.

If you have a class that finds, say, all the zip codes in a given
city, and it gives you a wrong answer, where is the problem likely to
be? In the class or in some database that it's searching? You can
verify that the class searches the data correctly but not that the
data is correct. Or perhaps you can, but that really belongs in some
other test.

--
Jim Janney
From: Lew on
Rhino wrote:
> Actually, my getLocales() method is really just a convenience method that
> massages the results of Locale.getAvailableLocales() itself.
>
> Just to be sure I'm using the term "convenience method" correctly, I'm
> referring to a method I write that uses existing Java API methods but
> that combines several lines of code into one or two. For example, since I

Yep.

> prefer my Locales list to be in alphabetical order, I've written this:
>
> public Map<String, String> getLocales() {
>
> Locale[] listOfLocales = Locale.getAvailableLocales();
>
> Map<String, String> locales = new TreeMap<String, String>();
> for (Locale singleLocale : listOfLocales) {
> locales.put(singleLocale.toString(), singleLocale.getDisplayName
> (locale));

Umm, what is 'locale' in this line? I mean, it's obvious that it's a
'Locale', but what is it?

> }
>
> return locales;
> }

Your 'listOfLocales' variable is, perhaps, not necessary.

That idiom also works if you want to retrieve the Locales themselves based on
name:

Map <String, Locale> locales = new TreeMap <String, Locale> ();

for( Locale loc : Locale.getAvailableLocales() )
{
locales.put( loc.getDisplayName(locale), loc );
}

or something like.

> As such, I don't know how to do a JUnit test on it, specifically how to
> generate an expected result that can be compared to my actual result. It
> seems self-evident that I have to get my expected result in a different
> way than I get the actual result, otherwise, I'm not proving anything.

Unit tests cannot do everything that the class under test does, otherwise the
unit test class would be the class under test. What unit tests do is test the
"happy path" and various corner cases to provide a high level of certainty
that the tested class will correctly handle the infinite variety of stuff
thrown at it in production. In other words, a unit test is really a sanity
check that takes care of the most likely issues. If a unit test could prevent
all possible errors, we'd never need logging.

For your case, you might test that the 'Map' has the same number of entries as
'getLocales()' has elements and that it correctly returns the right values for
some representative keys.

....
> Or is it the case that such a method CAN'T have its accuracy tested in
> this way and no such attempt should be made? Is it enough to prove that
> the method executes without throwing an exception?

You should go farther than that.

>>> --------------------------------
>>>
>>> Scenario 3 - getInstance()
>>>
>>> Given a hypothetical class named Fuzz where the constructors and
>>> getInstance() methods are:
>>>
>>> private Fuzz() {
>>> // do something
>>> }
>>>
>>> private Fuzz(Locale locale) {
>>> // do something
>>> // initialize instance variable for locale
>>> }
>>>
>>> public getInstance() {

Lew wrote:
>> Where is your return value?
>>
>> This won't even compile.
>>

Rhino wrote:
> Sorry, I just hacked that together to save a minute. I probably should
> have copied in a compiled example....

Oopsie. (Giggle)

>>> Would the following be adequate as JUnit tests for the getInstance()
>>> methods?
>>>
>>> public void testGetInstance() {
>>>
>>> Fuzz fuzz = Fuzz.getInstance();
>>> if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz");
>>> }
> ...
> So, if the constructor doesn't
> throw any exceptions and is public, you say that I should test that "the
> returned values exists and is not null".

Non-nullity of the return value should be handled by an 'assert' in the
factory method, and therefore not necessary to test in the unit test.
Existence is already guaranteed by the successful return of the factory method.

> What's my best way of doing that? Am I right in assuming that a simple
>
> if (Foo != null)

Ummm, 'Foo' is a class, right? It better be, and therefore that line will not
compile.

> will cover both of those?

How about 'assertNotNull( fuzz );'?

--
Lew
From: Lew on
Rhino wrote:
>> if (Foo == null) fail("Constructor failed to instantiate the class");

Eric Sosman wrote:
> Rhino, if you keep on spewing this sort of codecrap I'm going
> to shove that horn of yours firmly up the orifice that spews.

Rhino, the source of Eric's irritation is that despite apologizing profusely
multiple times for posting uncompilable code, you did it again anyway.

Apologies don't help much if you don't correct the behavior.

Also, never omit the curly braces in the statement bodies of 'if', 'while',
'for' and 'do...while' statements.

You'd best adhere to the discipline of providing only SSCCEs for a while
<http://sscce.org/>
until you gain more familiarity with the syntax rules for Java.

You won't know that it's an SSCCE unless you actually at least *compile* the
code you post, and really, you should run it first, too.

Doing that will help you. Failing to do that will cause the smartest and most
helpful respondents, such as Eric, not to.

--
Lew
From: Patricia Shanahan on
Rhino wrote:
....
> Actually, my getLocales() method is really just a convenience method that
> massages the results of Locale.getAvailableLocales() itself.
>
> Just to be sure I'm using the term "convenience method" correctly, I'm
> referring to a method I write that uses existing Java API methods but
> that combines several lines of code into one or two. For example, since I
> prefer my Locales list to be in alphabetical order, I've written this:
>
> public Map<String, String> getLocales() {
>
> Locale[] listOfLocales = Locale.getAvailableLocales();
>
> Map<String, String> locales = new TreeMap<String, String>();
> for (Locale singleLocale : listOfLocales) {
> locales.put(singleLocale.toString(), singleLocale.getDisplayName
> (locale));
> }
>
> return locales;
> }
>
> As such, I don't know how to do a JUnit test on it, specifically how to
> generate an expected result that can be compared to my actual result. It
> seems self-evident that I have to get my expected result in a different
> way than I get the actual result, otherwise, I'm not proving anything.

You seem to be assuming that a JUnit test requires an expected result.
Don't forget the assertTrue method, which lets you test arbitrary
conditions.

Patricia