From: Rhino on 18 Mar 2010 15:22 I think I understand the basics of using JUnit - I'm still using JUnit3 for the moment - but I want to ask some things that I don't find clear in the documentation that I've found. Would it be reasonable to say all of the following? 1. For each class that I develop, I should have one JUnit class that extends TestCase and that this TestCase class should test each of the methods in the class I developed? 2. When I look at the JUnit window in Eclipse to see the results of that TestCase class, all of them should have a Green icon beside them? In other words, should each test be written to show a positive result? That would seem to make life a lot easier in one way: whenever I ran a TestCase that was written that way, any bug would be easy to spot because it didn't have the Green icon beside it. 3. Is a TestSuite just a group of TestCases that can all be invoked from the same JUnit class? For instance, given a project Foo, would I typically have a single TestSuite for Foo that, when invoked, runs the TestCases for each of the classes that makes up Foo? Basically, I'm having a bit of confusion over exactly how much you put in each class that extends TestCase (sorry for the strange wording but I want to distinguish between the class that is being tested and the class that is doing the testing and don't know the most concise wording) and what a TestSuite should comprise. Also, I'm very uncertain about the individual methods in each class that extends TestCase and what sorts of results they should return. Should all test methods result in a Green icon? I can see where that would be very convenient: you simply run the test case and even if it has dozens of methods, you just scan down the list and make sure all of them have Green icons. If they do, all your tests just passed and you can move on to the next thing. On the other hand, I'm not completely sure how to accomplish that. I'm picturing a method like bar() which takes two input parameters. Whenever the values of the two input parameters are valid, bar() should produce a valid result, which I can predict and put in a test that would look like this: int actualResult = myclass.bar(4); int expectedResult = 2; assertTrue("The actual result, " + actualResult + ", does not equal the expected result, " + expectedResult, actualResult==expectedResult); But bar() also anticipates bad values for input parameters and throws IllegalArgumentException for those. What would my test for that look like? Any case I've ever written like that returns a Black icon. How would I write a case involving an Exception so that it gives a Green icon as the result? -- Rhino --- news://freenews.netfront.net/ - complaints: news(a)netfront.net ---
From: Eric Sosman on 18 Mar 2010 15:38 On 3/18/2010 3:22 PM, Rhino wrote: > I think I understand the basics of using JUnit - I'm still using JUnit3 > for the moment - but I want to ask some things that I don't find clear in > the documentation that I've found. > > Would it be reasonable to say all of the following? > > 1. For each class that I develop, I should have one JUnit class that > extends TestCase and that this TestCase class should test each of the > methods in the class I developed? Sort of, I'd say. Private and even package-private classes might get a waiver, the idea being that their "contracts" are only with the public classes that "employ" them. Non-public nested classes, same thing: If they're really just "implementation details" of their containing classes, they might not need separate testing. (For some inner classes, it won't be possible to test in isolation.) "Each method" may be a overkill, too. Getters and setters come to mind as "too simple to test" -- usually. I've never heard of anyone writing a unit test for the hashCode()/equals() pair (their agreement should be verified, but it's not clear that testing is the best way to go about it). > [...] Whenever > the values of the two input parameters are valid, bar() should produce a > valid result, which I can predict and put in a test that would look like > this: > > int actualResult = myclass.bar(4); > int expectedResult = 2; > assertTrue("The actual result, " + actualResult + ", does not equal the > expected result, " + expectedResult, actualResult==expectedResult); > > But bar() also anticipates bad values for input parameters and throws > IllegalArgumentException for those. What would my test for that look > like? Any case I've ever written like that returns a Black icon. How > would I write a case involving an Exception so that it gives a Green icon > as the result? try { int actual = myclass.bar(invalid); assertTrue("Got result " + actual + " from " + invalid + " instead of an exception", false); } catch (IllegalArgumentException ex) { // Thanks; I needed that! } -- Eric Sosman esosman(a)ieee-dot-org.invalid
From: Jim on 18 Mar 2010 17:13 On Thu, 18 Mar 2010 15:38:05 -0400, Eric Sosman <esosman(a)ieee-dot-org.invalid> wrote: >On 3/18/2010 3:22 PM, Rhino wrote: >> I think I understand the basics of using JUnit - I'm still using JUnit3 >> for the moment - but I want to ask some things that I don't find clear in >> the documentation that I've found. >> >> Would it be reasonable to say all of the following? >> >> 1. For each class that I develop, I should have one JUnit class that >> extends TestCase and that this TestCase class should test each of the >> methods in the class I developed? > > Sort of, I'd say. Private and even package-private classes >might get a waiver, the idea being that their "contracts" are only >with the public classes that "employ" them. Non-public nested >classes, same thing: If they're really just "implementation details" >of their containing classes, they might not need separate testing. >(For some inner classes, it won't be possible to test in isolation.) > > "Each method" may be a overkill, too. Getters and setters come >to mind as "too simple to test" -- usually. I've never heard of >anyone writing a unit test for the hashCode()/equals() pair (their >agreement should be verified, but it's not clear that testing is >the best way to go about it). <snip> Have to disagree about equals() at least. Having a unit test for equals ensures that when you make changes to your class you don't break the method. As me how I know ;-) Jim
From: Daniel Pitts on 18 Mar 2010 17:35 On 3/18/2010 12:38 PM, Eric Sosman wrote: > On 3/18/2010 3:22 PM, Rhino wrote: >> But bar() also anticipates bad values for input parameters and throws >> IllegalArgumentException for those. What would my test for that look >> like? Any case I've ever written like that returns a Black icon. How >> would I write a case involving an Exception so that it gives a Green icon >> as the result? > > try { > int actual = myclass.bar(invalid); > assertTrue("Got result " + actual + " from " + invalid > + " instead of an exception", false); > } > catch (IllegalArgumentException ex) { > // Thanks; I needed that! > } > I think there is a "fail(String )" method you can call instead of assertTrue(String, false). At least, on the versions of JUnit I have used. -- Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: Tom Anderson on 18 Mar 2010 17:51
On Thu, 18 Mar 2010, Rhino wrote: > I think I understand the basics of using JUnit - I'm still using JUnit3 > for the moment I'd strongly advise moving to 4 right away - there are some differences to get used to, so best to do that before you get comfortable with 3. > 1. For each class that I develop, I should have one JUnit class that > extends TestCase and that this TestCase class should test each of the > methods in the class I developed? There doesn't have to be a strict 1:1 relationship. Test classes are classes, and are subject to the same principles of design as any other classes - give each class a single responsibility, splitting classes that do too many different things. A responsibility could be "test that the Furnace class works", but it could also be "test that the Furnace class incinerates various kinds of rubbish properly", where you'd then have other classes to test other aspects of Furnace behaviour. You might also want more integrationish tests, which would involve the interaction of two classes - test that the ResourceLoader works properly when coupled to the JDBCDataStore. > 2. When I look at the JUnit window in Eclipse to see the results of that > TestCase class, all of them should have a Green icon beside them? Yes, absolutely. > In other words, should each test be written to show a positive result? Yes, absolutely. > That would seem to make life a lot easier in one way: whenever I ran a > TestCase that was written that way, any bug would be easy to spot > because it didn't have the Green icon beside it. Bingo. Eclipse has a button - the little red and blue squares at the top of the JUnit pane - that hides all green tests, leaving only failed and errored ones, which makes it even easier to spot the troublemakers. > 3. Is a TestSuite just a group of TestCases that can all be invoked from > the same JUnit class? Yes. > For instance, given a project Foo, would I typically have a single > TestSuite for Foo that, when invoked, runs the TestCases for each of the > classes that makes up Foo? Precisely. Although you might have several suite classes, and you might nest them. For instance, in our current project, we have an AllTests suite (this is quite a common name for such a thing, i think) that runs all the tests that are meaningful on a development machine. We have some extra tests which only make sense on the nightly build (which does some extra tasks which take longer, and which need to be tested), so we have a ServerBuildTests suite. We then have a super-suite AllTestsAndServerBuildTests, which runs both of the other suites. To be honest, those names probably aren't quite right, but hey, at least we have the tests. Note that Eclipse doesn't require you to have a suite to run all your tests - in the context menu for a source folder, there's Run As > JUnit Test, which will find all the tests in that package and run them. You can't use this in a non-Eclipse situation (like a command-line build, such as you might distribute, or use for a nightly build), but there are equivalents; i have build-and-test scripts which employ the following science: grep -rl --include='*.java' @Test "$TEST_SRC_DIR" | cut -d / -f 2- | cut -d . -f 1 | tr / . | xargs java -ea -classpath "$TEST_CLASSES_DIR:$CLASSES_DIR" org.junit.runner.JUnitCore > Basically, I'm having a bit of confusion over exactly how much you put > in each class that extends TestCase There's no easy answer to this. On the bright side, there are no hard and fast rules, so you can't get it wrong. Approach the matter as you would any other question of how much should go in a class, but don't sweat it too much. There tends to be fairly little coupling between test methods in a test class, so it's not a disaster if the classes that contain them are too big or too small. Where i work, our test classes very much tend to run to the too big end of the scale rather than the too small - i think there's one with thirty or so test methods. That really could do with breaking up, actually. > (sorry for the strange wording but I want to distinguish between the > class that is being tested and the class that is doing the testing and > don't know the most concise wording) I call that a test class. The target is the 'class under test'. > and what a TestSuite should comprise. > > Also, I'm very uncertain about the individual methods in each class that > extends TestCase and what sorts of results they should return. Should > all test methods result in a Green icon? Yes, absolutely. This is essential. Fundamental. > I can see where that would be very convenient: you simply run the test > case and even if it has dozens of methods, you just scan down the list > and make sure all of them have Green icons. If they do, all your tests > just passed and you can move on to the next thing. Not just convenient, essential. > On the other hand, I'm not completely sure how to accomplish that. I'm > picturing a method like bar() which takes two input parameters. Whenever > the values of the two input parameters are valid, bar() should produce a > valid result, which I can predict and put in a test that would look like > this: > > int actualResult = myclass.bar(4); Hey, what happened to the other parameter? > int expectedResult = 2; > assertTrue("The actual result, " + actualResult + ", does not equal the > expected result, " + expectedResult, actualResult==expectedResult); > > But bar() also anticipates bad values for input parameters and throws > IllegalArgumentException for those. What would my test for that look > like? Any case I've ever written like that returns a Black icon. How > would I write a case involving an Exception so that it gives a Green > icon as the result? Under JUnit 4: @Test(expected=IllegalArgumentException.class) public void testBarThrowsExceptionForInvalidParameters() { myclass.bar(-1); } Under JUnit 3: public void testBarThrowsExceptionForInvalidParameters() { try { myclass.bar(-1); } catch (IllegalArgumentException e) { return; } fail(); // this will only be reached if an exception is not thrown } Or some variation on that - the fail() could be inside the try, right after the call to bar, or you could have a boolean exceptionThrown = false, then set it to true in the catch block, then do assertTrue(exceptionThrown) at the end. HTH. tom -- I need a proper outlet for my tendency towards analytical thought. -- Geneva Melzack |