Please try to attend the tutorials once they start. Attending tutorials is certainly a higher priority than attending lectures.
The purpose of this tutorial is to ensure that you are comfortable with the Eclipse/Java/JUnit tools on DICE (or whichever alternative tools that you choose to work with).
Recall the Triangle source code we looked at on Friday in Week 1 — first the badly-implemented Triangle class itself:
Source for st.Triangle : |
---|
package st; public class Triangle { private int p; // Longest edge private int q; private int r; public Triangle(int s1, int s2, int s3) { // Ensure that p is the largest of the three. if(s1 > s2) { q = s2; if(s1 > s3) { p = s1; r = s3; } else { p = s3; r = s1; } } else { q = s1; if(s2 > s3) { p = s2; r = s3; } else { p = s3; r = s2; } } } public boolean isScalene() { return p > 0 && q > 0 && r > 0 && p < q + r && (q < r || q > r); } public boolean isEquilateral() { return p == q && q == r; } } |
Then the TriangleTestJ3 unit test (this is JUnit 3 style; see below for a JUnit 4 version).
JUnit 3 source for st.TriangleTestJ3 : |
---|
package st; import junit.framework.TestCase; public class TriangleTestJ3 extends TestCase { private Triangle t; public void setUp() { t = new Triangle(3, 4, 5); } public void testTriangle() { fail("Not yet implemented"); } public void testIsScalene() { assertTrue("t not scalene!?!", t.isScalene()); } public void testIsEquilateral() { assertFalse("t unexpectedly equilateral!", t.isEquilateral()); } } |
Here's the JUnit 4 version:
JUnit 4 source for st.TrianglTestJ4 : |
---|
package st; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class TrianglTestJ4 { private Triangle t; @Before public void init() throws Exception { t = new Triangle(3, 4, 5); } @Test public void scaleneOk() { assertTrue(t.isScalene()); } } |
And finally the AllTestsJ3 test suite:
Source for st.AllTestsJ3 : |
---|
package st; import junit.framework.Test; import junit.framework.TestSuite; public class AllTestsJ3 { public static Test suite() { TestSuite suite = new TestSuite("Test for st"); //$JUnit-BEGIN$ suite.addTestSuite(TriangleTestJ3.class); //$JUnit-END$ return suite; } } |
And the JUnit 4 version:
Source for st.AllTestsJ4 : |
---|
package st; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ st.TriangleTestJ4.class, }) public class AllTestsJ4 { // Everything's done by the annotations above. } |
Think of a series of test inputs and the results that you'd expect
for them, then create the appropriate tests. As I explained on Friday,
the test fixture mechanism is clumsy for instantiating and testing a lot
of objects, so you might prefer to get rid of the private Triangle
t;
and setUp()
, and do something like this:
Testing lots of Triangles (JUnit 3 style): |
---|
public void testIsEquilateral() { Triangle t = new Triangle(4, 5, 6); assertFalse("(4, 5, 6) unexpectedly equilateral!", t.isEquilateral()); t = new Triangle(1, 1, 1); assertTrue("(1, 1, 1) unexpectedly not equilateral!", t.isEquilateral()); … } |
You might also like to add a toString()
method to
Triangle
in order to help with debug messages.
These tests will quickly show that isScalene()
is
incorrect. Fix it.
It's really an error to allow construction of bad triangles, so it
makes sense to test these bad inputs in the constructor and throw an
exception of some kind for non-triangle parameters. Do this, including
adding a BadTriangleException
to your implementation. You
may need to add some throws
clauses to your code. You
should also find that after making these enhancements, you can simplify
the isScalene()
test.
As demonstrated in class, you can test that error conditions are detected and exceptions get thrown correctly too:
Testing to see that exceptions are thrown (JUnit3): |
---|
public void testTriangle() { try { // Some code which should cause an exception: Triangle q = new Triangle(0, 0, 0); // If we get here then the code didn't cause an exception, // and so the test has failed. fail("Exception not thrown: bad triangle accepted!!!"); } catch(ParticularExceptionWeAreTestingFor e) { // If we get here then the exception was thrown correctly. // We do nothing, and let successful execution continue. } … } |
This is much cleaner in JUnit 4:
Testing to see that exceptions are thrown (JUnit4): |
---|
@Test(expected = st.BadTriangleException.class) public void noBadTriangles() throws BadTriangleException { // Should cause an exception: t = new Triangle(0, 0, 0); } |
Implement a set of tests for the testTriangle method.
Version 1.5, 2010/01/21 19:01:21
Informatics Forum, 10 Crichton Street, Edinburgh, EH8 9AB, Scotland, UK
Tel: +44 131 651 5661, Fax: +44 131 651 1426, E-mail: school-office@inf.ed.ac.uk Please contact our webadmin with any comments or corrections. Logging and Cookies Unless explicitly stated otherwise, all material is copyright © The University of Edinburgh |