|
From: Rhino on 21 May 2010 09:47 Patricia Shanahan <pats(a)acm.org> wrote in news:WvSdnRf94rW73GvWnZ2dnUVZ_vudnZ2d(a)earthlink.com: > 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. > I'm not really familiar with assertTrue - I'm just getting back into Java and JUnit after a gap of a few years and I was never all that fluent with JUnit even before the gap. I'll look at the JUnit docs and see what I can learn there about the purpose and best uses of assertTrue.... Thanks for the suggestion, I'm sure it will be helpful once I understand it better ;-) -- Rhino
From: Patricia Shanahan on 21 May 2010 10:20 Arved Sandstrom wrote: .... > 5. Your tests are themselves defective. The sad truth is that if the > core source code you just wrote is riddled with defects, then so > probably are your tests. Main take-away here is, be aware that just > because all your unit tests pass, some not insignificant percentage of > those results are wrong. Although it is not 100% effective, there is some value in writing, and running, the test before implementing the feature. Start testing a method when it is just an empty stub. At that point, a test that passes is either useless or has a bug in it. Patricia
From: Patricia Shanahan on 21 May 2010 11:05 Rhino wrote: > Patricia Shanahan <pats(a)acm.org> wrote in .... >> 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. >> > I'm not really familiar with assertTrue - I'm just getting back into Java > and JUnit after a gap of a few years and I was never all that fluent with > JUnit even before the gap. I'll look at the JUnit docs and see what I can > learn there about the purpose and best uses of assertTrue.... I'll modify my suggestion from "Don't forget" to "Learn about". > > Thanks for the suggestion, I'm sure it will be helpful once I understand it > better ;-) Here's a possibly relevant example, a method that tests an Iterator<String> for non-empty, strictly increasing, no null elements. /** * Pass a non-empty String iterator with only non-null elements * in strictly * increasing order. */ private void testIteratorBehavior(Iterator<String> it) { assertTrue(it.hasNext()); String oldElement = it.next(); assertNotNull(oldElement); while (it.hasNext()) { String newElement = it.next(); assertNotNull(newElement); assertTrue(newElement.compareTo(oldElement) > 0); oldElement = newElement; } } Using this sort of technique you can test a structure for conforming to some known rules without using an expected value. Patricia
From: Jim Janney on 21 May 2010 12:35 Rhino <no.offline.contact.please(a)example.com> writes: > Eric Sosman <esosman(a)ieee-dot-org.invalid> wrote in > news:ht49d0$i91$1(a)news.eternal-september.org: > >> 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." >> > Okay, you've given me a broad principle and that is all well and good but > I do a lot better with at least one concrete example. It doesn't have to > be _my_ example either, just something that resembles something I'm > doing. > >>> 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. >> > I'm really not sure what you mean by "codecrap" here. I assume you're > saying that it won't compile but, in fact, this is a line from an actual > test case with the class name changed to Foo. Here is the full unit test, > WITHOUT the name change, copied and pasted directly from the test case > and I assure you that this does compile: > > public void testGetInstance() { > > StringUtils stringUtils = StringUtils.getInstance(); > if (stringUtils == null) fail("testGetInstance() failed"); > } > >>>> 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), > > Yes, I do in fact mean a factory method. And here are my constructors and > getInstance() methods, copied and pasted directly from the source: > > private StringUtils() { > > locale = Locale.getDefault(); > localizationUtils = LocalizationUtils.getInstance(locale); > locMsg = localizationUtils.getResources(locale, MSG_PREFIX); > msgFmt.setLocale(locale); > } > > private StringUtils(Locale myLocale) { > > locale = myLocale; > localizationUtils = LocalizationUtils.getInstance(locale); > locMsg = localizationUtils.getResources(locale, MSG_PREFIX); > msgFmt.setLocale(locale); > } > > public static StringUtils getInstance() { > return new StringUtils(); > } > > public static StringUtils getInstance(Locale myLocale) { > return new StringUtils(myLocale); > } > >> 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? >> > Yes, that's right. Oh, so _that's_ what you meant in your previous reply! > Again, when someone answers a question only with a generality, it's never > as clear for me as when I also hear a concrete "for instance'. I'm really > not being obtuse although I imagine it must seem like it.... > >>>> 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? >> > My theory is rather weak so I'm not really up on the meanings of "black > box" and "clear box" testing, let alone the subtle differences between > them. Also, I'm not writing the code for anyone but myself right now, > except that I _would_ like to get one project's code looking as > professional as possible so that I could present it to a prospective > client or employer as a portfolio of what I can do. (And then imitate > that in future projects as well as gradually retrofit other existing > projects with what I've learned). With that in mind, would a reasonable > employer/client likely find it acceptable that I just tested the methods > I wrote and overrode myself in my classes or are they going to see me as > the biggest idiot since the development of COBOL if I fail to observe > these subtleties? Speaking as someone who occasionally sits in on job interviews, I'm delighted when we find a candidate who's written any tests at all. Most of them haven't. We don't expect people to know more than we do (it would be great if they did) and we all learned as we went along and wish we understood it better. > >> 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. >> > I have no problem with that at all. If there are certain things I don't > need to cover in unit testing, that's perfectly fine. If you or anyone > else reading this could point me a good summary of what is and is not a > concern in unit testing, that would be very helpful. Again, I have > effectively NO formal training and what much of the on-the-job stuff I > have was learned many years ago. That means that my memory of the theory > is very incomplete at this point. In short, I don't know what the > prevailing theory is on exactly what should be covered by unit testing, > acceptance testing, regression testing, et. al. I'm not going to worry > about anything beyond unit testing for the moment but if anyone can point > me to a general - and hopefully fairly brief and example-laden - > discussion of the prevailing theories of testing, that would be very > helpful. In the specific case of a utility class, what I look for is clear Javadoc. I need to be able to decide, without wasting a lot of time, whether a method does what I need or not, and how it handles corner cases. For an example of how I like to see it done, go to http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringUtils.html and look at, say, the definition for center(java.lang.String, int) Notice that once you have a good definition of how the method should behave, writing a unit test for it is straightforward. Notice also that testing a utility class is very different from testing a program or an application framework. -- Jim Janney
From: Tom Anderson on 21 May 2010 14:13
On Fri, 21 May 2010, Arved Sandstrom wrote: > 3. Code coverage - Huge, IMO. How can you know that your unit tests or > integration tests (or even human-tester-driven acceptance tests) are > doing any good unless you know how much of the code is actually being > exercised? Code coverage is very simple to do, and for starters you > can't go wrong investigating Emma or Cobertura. These simply instrument > the Java bytecode, such that when the bytecode is executed (by any > mechanism) coverage counts by line/branch/method/class/package are > written to HTML or XML reports. Out of interest, do those play well with other things which modify bytecode, like JDO/JPA enhancers? tom -- 09F911029D74E35BD84156C5635688C0 -- AACS Licensing Administrator |