Embrace Unit Testing

  • 12,222 views
Uploaded on

The presentation contains a definition and survey of the benefits of Unit Testing, and a little coding example to get the feeling of Unit Testing using JUnit, EasyMock and XMLUnit.

The presentation contains a definition and survey of the benefits of Unit Testing, and a little coding example to get the feeling of Unit Testing using JUnit, EasyMock and XMLUnit.

More in: Technology , Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • very nice one, can you please explain how we can achieve the same when we need to deal with complex UI (Eclipse SWT/JFACE)...
    Are you sure you want to
    Your message goes here
  • good ppt
    if possible
    please mail
    ksubbaraju.tm@gmail.com
    Are you sure you want to
    Your message goes here
  • As a management instructor I appreciate viewing the function of others. This is among the best demonstration on planning I have viewed.
    Sharika
    http://financeadded.com http://traveltreble.com
    Are you sure you want to
    Your message goes here
  • good ppt...appreciate if you can send it to met meera_visa@yahoo.com
    Are you sure you want to
    Your message goes here
  • this is very nice
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
12,222
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
0
Comments
6
Likes
54

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. JUG Roma 26 th September 2006 “ Embrace Unit Testing” Alessio Pace alessio.pace [AT] gmail.com http://www.jroller.com/page/alessiopace
  • 2. 3 things about me..
    • Master Degree in Computer Engineering
    • Java fan
    • Just “Puccio” for the friends
  • 3. About this presentation
    • What you will find:
      • definition and survey of the benefits of Unit Testing
        • reusing material from the Web and books (see references at the end)
      • a little coding example to get the feeling of Unit Testing using JUnit, EasyMock and XMLUnit
    • What you won't find:
      • an in-depth explanation about the internals of the above testing frameworks
      • a Test Driven example
  • 4. Agenda
    • Introduction:
      • The programmer life without Unit Testing
      • What is and what is not Unit Testing
      • The benefits of Unit Testing
      • Bad rumours about Unit Testing, and the answers to them
    • Practical example in Java:
      • JUnit + EasyMock
      • JUnit + EasyMock + XMLUnit
  • 5. INTRODUCTION
  • 6. Programmer life without Unit Testing
    • Write a lot of code...and someday something doesn't work / stops working
    • Just fixing a bug is easy, but finding it can be a nightmare:
      • hours in front of the debugger
      • interact like a monkey with the browser or reading the output on console
    • Fixing it could break other parts
    • The bug could appear again later
  • 7. What is Unit Testing
    • A unit test is an automated and self-checked procedure used to validate that a particular module of source code works correctly
      • a module: a single Java class
    • The procedure is to write tests for all the methods or functions of the module
    • The class under test should be tested in isolation
  • 8. “A set of Unit Testing rules”
    • A test is not a unit test if:
      • It talks to the database
      • It communicates across the network
      • It touches the file system
      • It can't run at the same time as any of your other unit tests
      • You have to do special things to your environment (such as editing config files) to run it
      • You are not testing a class in isolation from other concrete classes
  • 9. The benefits of Unit Testing (1)
    • Isolate each part of the program and check that the individual parts work
    • Strict, written contract that the piece of code must satisfy
    • Allows to refactor code and make sure it still works correctly ( regression testing )
  • 10. The benefits of Unit Testing (2)
    • Simplifies integration :
      • testing the parts of a program first and then testing their integration
    • Provides documentation :
      • clients and other developers can look at the unit tests to gain a basic understanding of the APIs and determine how to use the module to fit their needs
    • Improves code quality :
      • code that cannot be easily tested is not factored properly
  • 11. The benefits of Unit Testing (3)
    • Separation of interface from implementation :
      • a class may have some collaborator classes, testing that class can frequently lead into testing the other classes..
      • unit test should never go outside of its own class boundary:
        • abstract an interface around the collaborator class, and implements that interface with a mock object (see later). This results in loosely coupled code, minimizing dependencies in the system
  • 12. Bad rumours about Unit Testing
    • “ It requires time, and I am always overscheduled”
    • “ It is a waste of time: if I change my classes, I have to rewrite the tests!”
    • “ My code is rock solid, I don't need tests!”
  • 13. Answers to the bad rumours (1/2)
    • The “I'm in hurry” issue leads to a vicious cycle:
      • more pressure you feel -> less tests you write
      • less tests you write -> less productive you are and the less stable your code becomes
      • the less productive and accurate you are -> more pressure you feel
  • 14. Answers to the bad rumours (2/2)
    • Unit Testing speeds up your development :
      • automated and self-checked code reduces the time to manually debug your code
      • writing unit tests immediately after you code new features (or even better, before ) lets you find bugs sooner and isolated (easy to correct)
    • Unit Testing lets you refactor safely:
      • a change in code that causes a regression is immediately found
  • 15. A short parenthesis on Refactoring
    • Refactoring , a definition:
      • “ A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behaviour” (“Refactoring”, Martin Fowler)
    • Unit Testing and Refactoring go together:
      • before refactoring a section of code you better have solid tests that cover it
      • test, small change, test, small change, test, ..
  • 16. PRACTICAL EXAMPLE
  • 17. Let's get into a coding example!
    • A practical example showing the very basics of:
      • JUnit 4.x + EasyMock 2.2
      • JUnit 4.x + EasyMock 2.2 + XMLUnit
    • See the References at the end for more tutorials and explanations about the internals of the frameworks
  • 18. Our example: a high level description
    • Suppose we are already given a IBookService interface, which defines a method to retrieve an IBook by its code
    • Suppose also we are already given an implementation of it: RemoteBookService
    • We want to implement and test:
      • a trivial CachedIBookService implementation, which decorates an IBookService by caching subsequent calls for the same book code value
  • 19. Our example: UML Class Diagram We have to implement and test the CachedBookService class
  • 20. Constructor implementation of CachedBookService public class CachedBookService implements IBookService { private IBookService remoteBookService ; public CachedBookService(IBookService bookService){ if(bookService == null){ throw new IllegalArgumentException(); } this.remoteBookService = bookService; } public IBookService getRemoteBookService() { return remoteBookService; } public IBook getBook(String code) throws NoSuchElementException { // implementation left out for the moment throw new NotImplementedException(); } } Ok, let's test the constructor
  • 21. How to automatically test the constructor?
    • We must check that:
      • when passing a valid argument the object state after the construction is correct (the instance variable remoteBookService is set)
      • when passing a null argument an IllegalArgumentException is thrown
    • We will use a testing framework: JUnit
  • 22. JUnit: description
    • JUnit is just a general testing framework which provides assertion methods
    • You can use it to do unit testing :
      • testing a single class in isolation, eventually using EasyMock (or other mock objects frameworks) to mock collaborators classes
    • You can use it to do integration testing :
      • testing the interactions of a class with real collaborator classes
    • Almost a de-facto standard in the Java field (but have a look also at TestNG ..)
  • 23. Writing a JUnit 4.x test class
    • A test class is just a Java class
    • Test methods must be annotated with @Test
    • Two configuration levels:
      • before/after each test method call ( @Before / @After annotated methods)
      • before/after the test class is processed ( @BeforeClass / @AfterClass annotated methods)
    • Launch the test class from an IDE (“run as JUnit Test”) or the command line
  • 24. Testing object state after constructor import static org.junit.Assert.*; import org.junit.Test; public class CachedBookServiceTest { @Test public void testConstructor () { // anonymous class to test in isolation CachedBookService constructor IBookService bookServiceParameter = new IBookService(){ public IBook getBook(String code) throws NoSuchElementException { return null; } }; CachedBookService cachedBookService = new CachedBookService(bookServiceParameter); assertNotNull ("Assert not null", cachedBookService.getRemoteBookService()); /* 3 identical ways to test the reference value: */ assertTrue ("Assert same reference", bookServiceParameter == cachedBookService.getRemoteBookService()); // assertSame ("Assert same reference", bookServiceParameter, cachedBookService.getRemoteBookService()); // assertEquals (“Assert same reference”, bookServiceParameter, cachedBookService.getRemoteBookService()) }
  • 25. Testing exception is thrown // CachedBookServiceTest.java @Test(expected=IllegalArgumentException.class) public void testConstructorWithNullArg () { // should throw IllegaArgumentException with null arg new CachedBookService( null ); } }
  • 26. Enjoy the green bar :-)
  • 27. Now let's implement getBook() method public class CachedBookService implements IBookService { private IbookService remoteBookService; private Map<String, IBook> cache; public CachedBookService(IBookService bookService){ if(bookService == null){ throw new IllegalArgumentException(); } this.remoteBookService = bookService; this.cache = new HashMap<String, IBook>(); } public IBook getBook(String code) throws NoSuchElementException { IBook ibook = cache.get(code); if(ibook != null){ return ibook; }else{ IBook result = this.remoteBookService.getBook(code); this.cache.put(code, result); return result; } } Ok, let's test getBook()
  • 28. How to test getBook()?
    • The class must be tested in isolation:
      • we don't want to rely on a concrete IBookService collaborator object
    • We must test the interactions of the class under test with the collaborator object:
      • first request for an IBook code must be delegated to the remoteBookService
      • following requests for the same IBook code must be served from the cache
    • We are going to use JUnit with a Mock Objects framework: EasyMock
  • 29. What are Mock Objects?
    • Most software units do not work alone, but collaborate with other units
    • To test a unit in isolation , the collaborators must be simulated
    • Mock objects have the same interfaces of the objects they mimic
      • a mock is configured to simulate the object behaviour that it replaces
      • In contrast to a stub , a mock object also verifies whether it is used as expected
  • 30. Why are Mocks useful?
    • Isolate bugs
    • Depend on an interface and not on an implementation (which couldn't exist yet)
    • Endo testing :
      • not just testing the output of a method, but testing the interactions of a unit with the collaborator object(s)
      • also called “interaction based testing” (as opposed to “state based testing” )
  • 31. EasyMock 2.2
    • EasyMock 2.2, two libraries:
      • one to generate mocks for interfaces only ( easymock )
      • one to generate mocks for non-final concrete classes and interfaces ( easymock-classextension )
    • Benefits:
      • hand writing mocks is not needed
      • supports compiler check and refactoring
      • supports method return values and exceptions
      • supports checking the order and count of method calls
      • ...
  • 32. How to get a mock object with EasyMock 2.2
    • create a Mock Object for the interface to simulate
    • record the expected behavior
    • switch the mock object to replay state
    • perform the method call to the class under test that is supposed to interact with the mock obejct
    • verify the mock has been used correctly
  • 33. Testing getBook() - 1 st test method @Test public void testGetBook () { // (1) create the mock for the collaborating object IBookService mockBookService = EasyMock.createMock(IBookService.class); // a mock with no behaviour as return value of getBook() IBook mockBook = EasyMock.createMock(IBook.class); // (2) record the expected behaviour EasyMock.expect(mockBookService.getBook(&quot;id123&quot;)).andReturn(mockBook); // (3) switch the mock to replay state EasyMock.replay(mockBookService); CachedBookService cachedBookService = new CachedBookService(mockBookService); // (4) perform the call to the class under test which interacts with the mock IBook result = cachedBookService.getBook(&quot;id123&quot;); assertSame(“Assert same reference”, mockBook, result); // (5) verify the mock has been used as expected EasyMock.verify(mockBookService); }
  • 34. Testing getBook() - 2 nd test method @Test public void testGetBookTwoDifferentCodes () { // (1) create the mock for the collaborating object IBookService mockBookService = EasyMock.createMock(IBookService.class); // a mock with no behaviour as return value of getBook() IBook mockBook = EasyMock.createMock(IBook.class); IBook mockBook2 = EasyMock.createMock(IBook.class); // (2) record two expected calls EasyMock.expect(mockBookService.getBook(&quot;id123&quot;)).andReturn(mockBook); EasyMock.expect(mockBookService.getBook(&quot;id456&quot;)).andReturn(mockBook2); // (3) switch the mock to replay state EasyMock.replay(mockBookService); CachedBookService cachedBookService = new CachedBookService(mockBookService); // (4) perform the call to the class under test which interacts with the mock IBook result = cachedBookService.getBook(&quot;id123&quot;); assertSame(“Assert same reference”, mockBook, result); IBook result2 = cachedBookService.getBook(&quot;id456&quot;); assertSame(“Assert same reference”, mockBook2, result2); // (5) verify the mock has been used as expected EasyMock.verify(mockBookService); }
  • 35. Testing getBook() - 3 rd test method @Test public void testGetSameBookTwoTimes () { IBookService mockBookService = EasyMock.createMock(IBookService.class); IBook mockBook = EasyMock.createMock(IBook.class); // record only one call EasyMock.expect(mockBookService.getBook(&quot;id123&quot;)).andReturn(mockBook); EasyMock.replay(mockBookService); CachedBookService cachedBookService = new CachedBookService(mockBookService); IBook result = cachedBookService.getBook(&quot;id123&quot;); assertSame(mockBook, result); IBook secondResult = cachedBookService.getBook(&quot;id123&quot;); assertSame(result, secondResult); EasyMock.verify(mockBookService); }
  • 36. Adding an IBookXmlSerializer
    • We are already given an IBookXmlSerializer interface to serialize an IBook to XML
    • We have to implement and test a simple IBookXmlSerializerImpl which writes an XML representation of an IBook
  • 37. IBookXmlSerializer
  • 38. IBookXmlSerializerImpl public class IBookXmlSerializerImpl implements IBookXmlSerializer { public String serialize(IBook book) { StringBuilder sb = new StringBuilder(&quot;&quot;); sb.append(&quot;<book>&quot;); sb.append(&quot; <code>&quot; + book.getCode() + &quot;</code>&quot;); sb.append(&quot; <title>&quot; + book.getTitle() + &quot;</title>&quot;); sb.append(&quot; <author>&quot; + book.getAuthor() + &quot;</author>&quot;); sb.append(&quot;</book>&quot;); return sb.toString(); } } Ok, let's test serialize()
  • 39. How to test serialize()?
    • We must check that the XML output is correct
    • We must test the class in isolation:
      • we can't rely on a concrete IBook implementation (we don't have it..)
    • We are going to use JUnit, EasyMock and XMLUnit
  • 40. Testing XML with XMLUnit
    • “ XMLUnit extends JUnit to simplify unit testing of XML”
    • “ It compares a control XML document to a test document or the result of a transformation, validates documents against a DTD, and compares the results of XPath expressions”
  • 41. IbookXmlSerializerTest - Part 1 import org.custommonkey.xmlunit.XMLTestCase; public class IBookXmlSerializerImplTest { private IBookXmlSerializer serializer; private IBook book; private XMLTestCase xmlTestCase; @Before public void setUp() throws Exception { this.serializer = new IBookXmlSerializerImpl(); this.book = EasyMock.createMock(IBook.class); this.xmlTestCase = new XMLTestCase(); } // .... The method annotated with @Before is executed before every @Test method execution
  • 42. IbookXmlSerializerTest - Part 2 @Test public void testSerialize() throws Exception { final String code = &quot;id1&quot;; EasyMock.expect(this.book.getCode()).andReturn(code); final String title = &quot;Unit Testing&quot;; EasyMock.expect(this.book.getTitle()).andReturn(title); final String author = &quot;Mario Rossi&quot;; EasyMock.expect(this.book.getAuthor()).andReturn(author); // switch to replay state EasyMock.replay(this.book); String xml = this.serializer.serialize(book); this.xmlTestCase.assertXpathExists(&quot;/book&quot;, xml); this.xmlTestCase.assertXpathEvaluatesTo(code, &quot;/book/code&quot;, xml); this.xmlTestCase.assertXpathEvaluatesTo(title, &quot;/book/title&quot;, xml); this.xmlTestCase.assertXpathEvaluatesTo(author, &quot;/book/author&quot;, xml); // verify mock EasyMock.verify(this.book); }
  • 43. If you appreciated Unit Testing...
    • ...you will want to try also:
      • Test Driven Development (TDD)
      • Continous Integration
      • Test Coverage tools
      • ..
  • 44. Test coverage with Cobertura
  • 45.
      • Open discussion
  • 46. Some references 1/2
    • Wikipedia:
      • http://en.wikipedia.org/wiki/Unit_testing
      • http://en.wikipedia.org/wiki/Mock_object
    • “ A Set of Unit Testing Rules” by Michael Feathers:
      • http://www.artima.com/weblogs/viewpost.jsp?thread=126923
    • “ Extreme Programing Explained / Installed” by Kent Beck / Ron Jeffries
    • “ Refactoring” by Martin Fowler
    • “ JUnit Test Infected: Programmers Love Writing Tests”:
      • http://junit.sourceforge.net/doc/testinfected/testing.htm
    • JUnit 4.x Cookbok:
      • http://junit.sourceforge.net/doc/cookbook/cookbook.htm
  • 47. Some references 2/2
    • “ Endo-Testing: Unit Testing with Mock Objects”:
      • www.connextra.com/aboutUs/mockobjects.pdf
    • EasyMock 2.2 Documentation:
      • http://easymock.org/EasyMock2_2_Documentation.html
      • http://easymock.org/EasyMock2_2_ClassExtension _Documentation.html
    • “ Partial Mocks with EasyMock”:
      • http://www.jroller.com/page/alessiopace?entry=partial_mocks_with_easymock
    • “ Making more objects mockable with ASM Definalizer”
      • http://sixlegs.com/blog/java/definalizer.html
    • XMLUnit:
      • http://xmlunit.sourceforge.net/