1 / 41

Unit Testing

Software Engineering Lecture XXX. Unit Testing. Bartosz Walter <Bartek.Walter@man.poznan.pl>. Agenda. JUnit – a unit testing library for Java Guidelines for creating test cases Smells in tests Implementation tasks. RomanNumberTest. Schemat klas jUnit. Test. TestResult. TestCase.

normat
Download Presentation

Unit Testing

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Software Engineering Lecture XXX Unit Testing Bartosz Walter <Bartek.Walter@man.poznan.pl>

  2. Agenda JUnit – a unit testing library for Java Guidelines for creating test cases Smells in tests Implementation tasks

  3. RomanNumberTest Schemat klas jUnit Test TestResult TestCase TestSuite

  4. void testXXXX() MyTest void testYYYY() void testZZZZ() TestCase MyTest(name) void setUp()  void testXXXX() void testYYYY() void testZZZZ() void testWWWW() void tearDown()  junit.framework.TestCase

  5. StudentTest.java Student.java + setUp() + getName() + testGetName() + getAge() + testGetAge() + computeLevel() + testComputeLevel() + tearDown() Klasa i jej klasa testowa Utworzenie instancji klasy Student – Student student Usunięcie instancji klasy Student

  6. void testXXXX() MyTest void testYYYY() void testZZZZ() TestCase MyTest(name) void setUp()  void testXXXX() void testYYYY() void testZZZZ() void testWWWW() void tearDown()  junit.framework.TestCase

  7. Simplest test possible... RomanNumberTest(name) public RomanNumberTest(name){super(name);} void setUp() public void setUp() { rn1 = new RomanNumber(5); rn2 = new RomanNumber(20);} void testSimple() public void testSimple()throws Exception { String str = rn1.toString(); assertEquals(str, "V"); } void tearDown() public void tearDown() {rn1 = null; rn2 = null;}

  8. Failure vs. error Failure: • anticipated violation of the test assertion • signals that the test actually fails Error: • unanticipated exception caught by the test runner • the test could not be run properly

  9. Failure vs. error public void testNonexistentFileRead() throws IOException { try { File file = new File("doesNotExist.txt"); FileReader reader = new FileReader(file); assertEquals('a', (char) reader.read()); fail("Read from a nonexistent file?!"); } catch (FileNotFoundException success) {} } public void testExistingFileRead() throws IOException { // exists.txt created in setup(), perhaps File file = new File("exists.txt"); FileReader reader = new FileReader(file); assertEquals('a', (char) reader.read()); }

  10. Basic functionality of a TestCase Groups of methods: • equality tests • void assertEquals([msg], expected, actual) • identity tests • void assertSame([msg], expected, actual) • void assertNotSame ([msg], expected, actual) • boolean tests • void assertTrue([msg], condition) • void assertFalse([msg], condition) • null tests • void assertNull([msg], object) • void assertNotNull([msg], object) • unconditional failure • void fail([msg])

  11. Creating TestSuites statically public class RomanNumberTest extends TestCase { public RomanNumberTest(String name) { super(name); } // testing methods public void testSimpleConv() {} public void testAddition() {} public static Test suite() { TestSuite suite = new TestSuite(); suite.addTest(new MyTest("testSimpleConv")); suite.addTest(new MyTest("testAddition")); return suite; } }

  12. Creating TestSuites dynamically public class RomanNumberTest extends TestCase { public RomanNumberTest(String name) { super(name); } // testing methods public void testSimpleConv() {} public void testAddition() {} public static Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(MyTest.class) return suite; } }

  13. Guidelines for creating TestCases Don't use constructor for initializing the TestCase public class SomeTest extends TestCase { public SomeTest (String testName) { super (testName); // Perform test set-up } } junit.framework.AssertionFailedError: Cannot instantiate test case: test1 at junit.framework.Assert.fail(Assert.java:143)     at junit.framework.TestSuite$1.runTest(TestSuite.java:178) at junit.framework.TestCase.runBare(TestCase.java:129)   at junit.framework.TestResult$1.protect(TestResult.java:100)  ...

  14. Guidelines for creating TestCases Don't use constructor for initializing the TestCase public class SomeTest extends TestCase { public SomeTest (String testName) { super (testName); } public void setUp() { // Perform test set-up } } java.lang.IllegalStateException: Oops at bp.DTC.setUp(DTC.java:34)   at junit.framework.TestCase.runBare(TestCase.java:127) at junit.framework.TestResult$1.protect(TestResult.java:100) ...

  15. Guidelines for creating TestCases Don't assume the order in which tests within a TestCase are executed Avoid writing TestCases with side effects public class SomeTestCase extends TestCase { public SomeTestCase (String testName) { super (testName); } public void testDoThisFirst () { } public void testDoThisSecond () { } }

  16. Guidelines for creating TestCases Don't assume the order in which tests within a TestCase are executed Avoid writing TestCases with side effects public class SomeTestCase extends TestCase { public void testDoThisFirst () { } public void testDoThisSecond () { } public static Test suite() { suite.addTest(new SomeTestCase("testDoThisFirst";)); suite.addTest(new SomeTestCase("testDoThisSecond";)); return suite; } }

  17. Guidelines for creating TestCases Avoid using hardcoded resources Write self-contained tests Place tests in the same packages as source code public class SomeTestCase extends TestCase { public void setUp () {    FileInputStream inp ("C:\\TestData\\dataSet1.dat"); // .. } }

  18. Guidelines for creating TestCases Avoid using hardcoded resources Write self-contained tests Place tests in the same packages as source code public class SomeTestCase extends TestCase { public void setUp () { InputStream inp = class.getResourceAsStream (this.getClass (), "dataSet1.dat"); } }

  19. Guidelines for creating TestCases Avoid time/locale-sensitive tests Date date = DateFormat.getInstance().parse("dd/mm/yyyy"); Calendar cal = Calendar.getInstance(); Cal.set(yyyy, mm-1, dd); Date date = Calendar.getTime(); Locale locale = Locale.getDefault();

  20. Guidelines for creating TestCases Use JUnit assert/fail methods for throwing Exceptions Don't catch exceptions unless they are expected to be thrown public void exampleTest() { try { // do some testing } catch (SomeApplicationException ex) { fail ("Caught SomeApplicationException exception"); } }

  21. Guidelines for creating TestCases If the test should pass on exception thrown, catch the exception within the test and place fail() if it is not thrown public void testIndexOutOfBoundsException() { ArrayList emptyList = new ArrayList(); try { Object o = emptyList.get(0); fail("IndexOutOfBoundsException expected"); } catch (IndexOutOfBoundsException success) { } }

  22. Guidelines for creating TestCases Use JUnit assert/fail methods for throwing Exceptions Don't catch exceptions unless they are expected to be thrown public void exampleTest () throws SomeApplicationException { // do some test }

  23. Guidelines for creating TestCases Beware of floating-point comparison errors assertEquals ("The result is different from what is expected", result, expected); assertEquals ("The result is different from what is expected", 0.05 + 0.05, 1/10.0); assertEquals ("The result is definitely different from what is expected ", result, expected, delta); assertEquals ("The result is definitely different from what is expected", 0.05 + 0.05, 1/10.0, 0.01);

  24. Guidelines for creating TestCases Testing protected and private methods Protected: • Place the tests in the same package as the classes under test. Private: • avoid • use Java Reflection to call a private method

  25. | +--src | | | +--com | | | +--xyz | | | +--SomeClass.java +--test | +--com | +--xyz | +--SomeClassTest.java com.xyz.SomeClass com.xyz.SomeClassTest Guidelines for creating TestCases Organizing files in catalog

  26. Task 1 Write tests for existing code of RomanNumber class

  27. RomanNumber class RomanNumber { // initialize with an Arabic year public RomanNumber(int number); // initialize with a Roman year public RomanNumber(String number); // return the Roman value public String toRoman(); // return the Arabic value public int toArabic(); // return a Collection of legal Roman symbols public static Collection getRomanSymbols(); }

  28. Task 2 Implement RomanNumber class using test-first approach.

  29. Testing first TestCase: • INPUT: 1, EXPECTED: "I" Implementation: String toArabic(int num) { return "I"; }

  30. Testing first TestCase: • INPUT: 2, EXPECTED: "II" Implementation: String toArabic(int num) { if (num == 1) return "I"; else return "II"; }

  31. Testing first TestCase: • INPUT: 3, EXPECTED: "III" Implementation: String toArabic(int num) { if (num == 1) return "I"; else if (num == 2) return "II"; else return "III"; }

  32. Testing first TestCase: • INPUT: 3, EXPECTED: "III" Implementation: String toArabic(int num) { while (num-- > 0) result += "I"; return result; } Refactoring

  33. Testing first TestCase: • INPUT: 4, EXPECTED: "IV" Implementation: String toArabic(int num) { if (num < 4) while (num-- > 0) result += "I"; return result; } return "IV"; }

  34. Testing first TestCase: • INPUT: 5, EXPECTED: "V" Implementation: String toArabic(int num) { if (num < 4) while (num-- > 0) result += "I"; return result; } else if (num == 4) { return "IV"; } else { return "V"; } }

  35. Testing first TestCase: • INPUT: 6, EXPECTED: "VI" Implementation: String toArabic(int num) { if (num < 4) while (num-- > 0) result += "I"; return result; } else if (num == 4) { return "IV"; } else if (num == 5) { return "V"; } else return "VI"; }

  36. Testing first TestCase: • INPUT: 8, EXPECTED: "VIII" Implementation: String toArabic(int num) { if (num < 4) while (num-- > 0) result += "I"; return result; } else if (num == 4) { return "IV"; } else { result = "V"; while (num-- > 5) result += "I"; return result; } } Refactoring

  37. Testing first TestCase: • INPUT: 9, EXPECTED: "IX" Implementation: String toArabic(int num) { // 1..4 .. else if (num < 9) { result = "V"; while (num-- > 5) result += "I"; return result; } else { return "IX"; } }

  38. Testing first TestCase: • INPUT: 10, EXPECTED: "X" Implementation: String toArabic(int num) { // 1..4 .. else if (num < 9) { result = "V"; while (num-- > 5) result += "I"; return result; } else (num == 9) { return "X"; } else { return "IX"; }

  39. Testing first TestCase: • INPUT: 1976, EXPECTED: "MCMLXXVI" Implementation: private class ConvSymbols {int arabic, String roman} {{1,I}, {4,IV}, {5,V}, {9,IX}, {10,X}, {40,XL}, ...} String toArabic(int num) { for (int i = 0; i < sizeof(symbols); i++) { Symbol sym = symbols[i]; while (num >= symbol.arabic) { num -= symbol.arabic; result += symbol.roman; } } } Refactoring

  40. Bibliography • JUnit, http://www.junit.org/ • Test Infected – Programmers love writing tests, http://junit.sourceforge.net/doc/testinfected/testing.htm • JUnit Cook's Tour, http://junit.sourceforge.net/doc/cookstour/cookstour.htm • Unit-testing Tools, http://www.xprogramming.com/software.htm

  41. Q&A ?

More Related