|
From: Rhino on 20 May 2010 13:48 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. -------------------------------- Scenario 2 - Constructors Given a hypothetical class named Foo where the constructor is: public Foo () { //anything from no code at all to umpteen lines } is this adequate as a JUnit test? public void testFoo() { Foo myFoo = new Foo(); if (!myFoo instanceof Foo) fail ("Failed to instantiate Foo"); } If not, what would be a better test? -------------------------------- 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() { return Foo(); } public getInstance(Locale locale) { return Foo(locale); } Is it necessary to write JUnit tests for the constructors, given that they are private? 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"); } public void testGetInstancelocale() { Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr")); if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"): } If not, what tests would be better? -------------------------------- Lastly - and thanks for bearing with me this far - is it normal practice to write JUnit tests for all methods that are in parent classes of the class being tested? For example, while writing tests for one of my classes, the wizard in Eclipse asked if I wanted to produce test methods to test methods of Object like equals() and wait(). Should I be writing tests for those methods as well as for those in my own class? I'm inclined to assume that the methods in Object, for example, have already been thoroughly tested and further testing by me seems redundant. Even parent classes that I myself wrote would presumably have had their own sets of JUnit Tests. Then again, the Eclipse developers presumably put that functionality in there for a reason so I'm left unclear about whether I should be trying to write tests for them too. -- Rhino
From: Lew on 20 May 2010 14:27 On 05/20/2010 01:48 PM, Rhino wrote: > 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. There may be several "right" answers to your questions. I will take a stab at some of them. > -------------------------------- > > 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 When the target "moves", write new tests. A unit test should test the behaviors of the methods given the domain of inputs and range of desired outputs or responses. Thus, given your scenario: > 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 Your current JVM doesn't have new Locales, so writing for ones that don't exist is clearly not possible. However, you can use <http://java.sun.com/javase/6/docs/api/java/util/Locale.html#getAvailableLocales()> to return an array of all currently available locales, and for-loop through them in your unit test: for ( Locale loc : Locale.getAvailableLocales() ) { assertTrue( "insane", sanityCheck( loc )); } > 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. > > -------------------------------- > > Scenario 2 - Constructors > > Given a hypothetical class named Foo where the constructor is: > > public Foo () { > //anything from no code at all to umpteen lines > } > > is this adequate as a JUnit test? > > public void testFoo() { > > Foo myFoo = new Foo(); > if (!myFoo instanceof Foo) fail ("Failed to instantiate Foo"); > } > > If not, what would be a better test? No, it's ridiculous. It is literally impossible for 'new Foo()' to return an instance of something that is not an instance of Foo, so checking for that is wacky. Checking that the constructor does not throw an exception is what you want. > -------------------------------- > > 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() { Where is your return value? This won't even compile. > return Foo(); > } > > public getInstance(Locale locale) { > > return Foo(locale); > } Where is your return value? This won't even compile. > Is it necessary to write JUnit tests for the constructors, given that > they are private? Write a test for the method, after you get it to compile. Normally you don't unit-test private or package-private methods, as they are not part of the published contract. Unit tests usually test the public contract. > 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"); > } If 'getInstance()', for which you did not show a return type, has a return type of 'Fuzz', then testing that the returned value is an instance of that type is wacky. The compiler guarantees it, so a run-time test is silly. You want to test what happens at run time, i.e., that the returned value exists, is not null, and there was no exception. Actually, it's also valid to test that there is an exception thrown if initial conditions demand it. For example, testing a constructor that takes an argument that must not be null, you might pass a null argument and confirm the 'IllegalArgumentException' from the constructor. It's just plain foolish to test that the type of the result matches what the compiler already guarantees is the type of the result. Unit tests are for run-time behaviors. > public void testGetInstancelocale() { > > Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr")); > if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"): > } > > If not, what tests would be better? > -------------------------------- > > Lastly - and thanks for bearing with me this far - is it normal practice > to write JUnit tests for all methods that are in parent classes of the > class being tested? For example, while writing tests for one of my Depends. > classes, the wizard in Eclipse asked if I wanted to produce test methods > to test methods of Object like equals() and wait(). Should I be writing Not sure how you'd write a test for 'wait()'. Writing a test for 'equals()' makes sense IF the class overrides 'equals()', in which case you'd also test that 'hashCode()' and 'toString()' match, as should 'compareTo()' if the class implements 'Comparable<YourType>'. It is quite important that those overrides be consistent. > tests for those methods as well as for those in my own class? I'm > inclined to assume that the methods in Object, for example, have already > been thoroughly tested and further testing by me seems redundant. Even Depends. Did you override them? > parent classes that I myself wrote would presumably have had their own > sets of JUnit Tests. Then again, the Eclipse developers presumably put > that functionality in there for a reason so I'm left unclear about > whether I should be trying to write tests for them too. The reason is that you routinely override methods like 'equals()' (and 'hashCode()', 'toString()' and 'compareTo()' with it). -- Lew
From: Eric Sosman on 20 May 2010 16:04 On 5/20/2010 1:48 PM, Rhino wrote: > [...] > Scenario 2 - Constructors > > Given a hypothetical class named Foo where the constructor is: > > public Foo () { > //anything from no code at all to umpteen lines > } > > is this adequate as a JUnit test? > > public void testFoo() { > > Foo myFoo = new Foo(); > if (!myFoo instanceof Foo) fail ("Failed to instantiate Foo"); > } This is inadequate because it won't compile. Insert the missing parentheses and it's not inadequate, but it's pointless: if the `new' completes without throwing an exception, `myFoo' *will* be an instance of Foo -- in fact, it will be an instance of Foo exactly, and not even of a Foo subclass. 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. > 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() { > > return Foo(); > } > > public getInstance(Locale locale) { > > return Foo(locale); > } > > Is it necessary to write JUnit tests for the constructors, given that > they are private? No, for two reasons. First, since the constructors are private you can't call them anyhow. Second, the code won't compile. > 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"); > } Inadequate because (and this is becoming tiresome; I *wish* people would stop posting garbage and pretending it's code samples!) the code won't compile. 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. > public void testGetInstancelocale() { > > Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr")); > if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"): > } (Broken) won't (record) compile (broken) won't (record) compile ... > If not, what tests would be better? Something that compiles would be better. "Hello, world!" for example, would be better -- not much of a test, I'll grant, but it would be better. > Lastly - and thanks for bearing with me this far - is it normal practice > to write JUnit tests for all methods that are in parent classes of the > class being tested? For example, while writing tests for one of my > classes, the wizard in Eclipse asked if I wanted to produce test methods > to test methods of Object like equals() and wait(). Should I be writing > tests for those methods as well as for those in my own class? I'm > inclined to assume that the methods in Object, for example, have already > been thoroughly tested and further testing by me seems redundant. Even > parent classes that I myself wrote would presumably have had their own > sets of JUnit Tests. Then again, the Eclipse developers presumably put > that functionality in there for a reason so I'm left unclear about > whether I should be trying to write tests for them too. 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"))'. -- Eric Sosman esosman(a)ieee-dot-org.invalid
From: Rhino on 20 May 2010 16:37 Lew <noone(a)lewscanon.com> wrote in news:ht3uv3$h2e$1(a)news.albasani.net: > On 05/20/2010 01:48 PM, Rhino wrote: >> 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. > > There may be several "right" answers to your questions. I will take a > stab at some of them. > >> -------------------------------- >> >> 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 > > When the target "moves", write new tests. > > A unit test should test the behaviors of the methods given the domain > of inputs and range of desired outputs or responses. Thus, given your > scenario: > >> 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 > > Your current JVM doesn't have new Locales, so writing for ones that > don't exist is clearly not possible. However, you can use > <http://java.sun.com/javase/6/docs/api/java/util/Locale.html#getAvailab > leLocales()> > > to return an array of all currently available locales, and for-loop > through them in your unit test: > > for ( Locale loc : Locale.getAvailableLocales() ) > { > assertTrue( "insane", sanityCheck( loc )); > } > >> 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. >> 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. But the same situation applies to things that aren't based on convenience methods. A list of telephone area codes or the names of all chiropractors in Ohio or any of a thousand other results from methods are also "moving targets". I'm really not sure how to test those. I can certainly execute the methods and prove that they didn't throw an exception but how can I verify that they are giving full and complete information? 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? >> -------------------------------- >> >> Scenario 2 - Constructors >> >> Given a hypothetical class named Foo where the constructor is: >> >> public Foo () { >> //anything from no code at all to umpteen lines >> } >> >> is this adequate as a JUnit test? >> >> public void testFoo() { >> >> Foo myFoo = new Foo(); >> if (!myFoo instanceof Foo) fail ("Failed to instantiate Foo"); >> } >> >> If not, what would be a better test? > > No, it's ridiculous. It is literally impossible for 'new Foo()' to > return an instance of something that is not an instance of Foo, so > checking for that is wacky. Checking that the constructor does not > throw an exception is what you want. > Ah, now it starts to make sense.... > >> -------------------------------- >> >> 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() { > > Where is your return value? > > This won't even compile. > Sorry, I just hacked that together to save a minute. I probably should have copied in a compiled example.... >> return Foo(); >> } >> >> public getInstance(Locale locale) { >> >> return Foo(locale); >> } > > Where is your return value? > > This won't even compile. > >> Is it necessary to write JUnit tests for the constructors, given that >> they are private? > > Write a test for the method, after you get it to compile. > > Normally you don't unit-test private or package-private methods, as > they are not part of the published contract. Unit tests usually test > the public contract. > Excellent, that makes sense to me. >> 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"); >> } > > If 'getInstance()', for which you did not show a return type, has a > return type of 'Fuzz', then testing that the returned value is an > instance of that type is wacky. The compiler guarantees it, so a > run-time test is silly. You want to test what happens at run time, > i.e., that the returned value exists, is not null, and there was no > exception. > > Actually, it's also valid to test that there is an exception thrown if > initial conditions demand it. For example, testing a constructor that > takes an argument that must not be null, you might pass a null > argument and confirm the 'IllegalArgumentException' from the > constructor. > That makes perfectly good sense to me. 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". What's my best way of doing that? Am I right in assuming that a simple if (Foo != null) will cover both of those? > It's just plain foolish to test that the type of the result matches > what the compiler already guarantees is the type of the result. Unit > tests are for run-time behaviors. > Fair enough. I couldn't quite see the point of the test either but thought I'd check it out with people that knew more than me. >> public void testGetInstancelocale() { >> >> Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr")); >> if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"): >> } >> >> If not, what tests would be better? >> -------------------------------- >> >> Lastly - and thanks for bearing with me this far - is it normal >> practice to write JUnit tests for all methods that are in parent >> classes of the class being tested? For example, while writing tests >> for one of my > > Depends. > >> classes, the wizard in Eclipse asked if I wanted to produce test >> methods to test methods of Object like equals() and wait(). Should I >> be writing > > Not sure how you'd write a test for 'wait()'. Writing a test for > 'equals()' makes sense IF the class overrides 'equals()', in which > case you'd also test that 'hashCode()' and 'toString()' match, as > should 'compareTo()' if the class implements 'Comparable<YourType>'. > It is quite important that those overrides be consistent. > >> tests for those methods as well as for those in my own class? I'm >> inclined to assume that the methods in Object, for example, have >> already been thoroughly tested and further testing by me seems >> redundant. Even > > Depends. Did you override them? > Nope. >> parent classes that I myself wrote would presumably have had their >> own sets of JUnit Tests. Then again, the Eclipse developers >> presumably put that functionality in there for a reason so I'm left >> unclear about whether I should be trying to write tests for them too. > > The reason is that you routinely override methods like 'equals()' (and > 'hashCode()', 'toString()' and 'compareTo()' with it). > Okay, that makes sense: if I override a method inherited from the parent, I should test the overridden method to make sure I didn't mess something up. -- Rhino
From: Rhino on 20 May 2010 16:47
Eric Sosman <esosman(a)ieee-dot-org.invalid> wrote in news:ht44ki$8rm$1 @news.eternal-september.org: > On 5/20/2010 1:48 PM, Rhino wrote: >> [...] >> Scenario 2 - Constructors >> >> Given a hypothetical class named Foo where the constructor is: >> >> public Foo () { >> //anything from no code at all to umpteen lines >> } >> >> is this adequate as a JUnit test? >> >> public void testFoo() { >> >> Foo myFoo = new Foo(); >> if (!myFoo instanceof Foo) fail ("Failed to instantiate Foo"); >> } > > This is inadequate because it won't compile. Sorry!! I just dashed that off quickly from memory and I obviously missed a few bits.... It was really just meant to be illustrate a standard constructor but perhaps I should have lifted one from an actual class (or omitted the class code altogether).... > Insert the > missing parentheses and it's not inadequate, but it's pointless: > if the `new' completes without throwing an exception, `myFoo' > *will* be an instance of Foo -- in fact, it will be an instance > of Foo exactly, and not even of a Foo subclass. > > 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 if (Foo == null) fail("Constructor failed to instantiate the class"); >> 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() { >> >> return Foo(); >> } >> >> public getInstance(Locale locale) { >> >> return Foo(locale); >> } >> >> Is it necessary to write JUnit tests for the constructors, given that >> they are private? > > No, for two reasons. First, since the constructors are private > you can't call them anyhow. Second, the code won't compile. > >> 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"); >> } > > Inadequate because (and this is becoming tiresome; I *wish* > people would stop posting garbage and pretending it's code samples!) > the code won't compile. > Sorry!! > 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? >> public void testGetInstancelocale() { >> >> Fuzz fuzz = Fuzz.getInstance(new Locale("FR", "fr")); >> if (!fuzz instanceof Fuzz) fail("Failed to instantiate Fuzz"): >> } > > (Broken) won't (record) compile (broken) won't (record) compile Again, sorry.... > >> If not, what tests would be better? > > Something that compiles would be better. "Hello, world!" for > example, would be better -- not much of a test, I'll grant, but it > would be better. > >> Lastly - and thanks for bearing with me this far - is it normal practice >> to write JUnit tests for all methods that are in parent classes of the >> class being tested? For example, while writing tests for one of my >> classes, the wizard in Eclipse asked if I wanted to produce test methods >> to test methods of Object like equals() and wait(). Should I be writing >> tests for those methods as well as for those in my own class? I'm >> inclined to assume that the methods in Object, for example, have already >> been thoroughly tested and further testing by me seems redundant. Even >> parent classes that I myself wrote would presumably have had their own >> sets of JUnit Tests. Then again, the Eclipse developers presumably put >> that functionality in there for a reason so I'm left unclear about >> whether I should be trying to write tests for them too. > > 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! Thanks!! -- Rhino |