Groovy Testing


Published on

A short introduction to Groovy testing techniques

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Groovy Testing

  1. 1. Groovy testing Davide Rossi <ul><li>Jug Milano, 19/02/2009 </li></ul>
  2. 2. Contents <ul><li>- Groovy built-in testing framework </li></ul><ul><li>- Unit test in Groovy: GroovyTestCase </li></ul><ul><ul><ul><li>- Testing for exceptions </li></ul></ul></ul><ul><li>- Groovy Mock and Stub </li></ul><ul><ul><ul><li>- The Java way: easymock, jMock... </li></ul></ul></ul><ul><ul><ul><li>- The Groovy way: using Categories </li></ul></ul></ul><ul><ul><ul><li>- The Groovy way: using ExpandoMetaClass </li></ul></ul></ul><ul><ul><ul><li>- The Groovy way: using Expandos and Maps </li></ul></ul></ul><ul><ul><ul><li>- The Groovy way: using stubFor and mockFor </li></ul></ul></ul><ul><li>- Testing Grails Actions </li></ul><ul><li>- Conclusion </li></ul>
  3. 3. Groovy testing framework <ul><li>- Groovy can be used to test Groovy and Java code </li></ul><ul><li>- Groovy has built-in support for Junit framework </li></ul><ul><ul><li>- GroovyTestCase extends Junit TestCase </li></ul></ul><ul><ul><li>- Adds many assertion methods (assertToString, AssertArrayEquals, shouldFail...) </li></ul></ul><ul><li>- Assertions are parts of the language </li></ul><ul><ul><li>ex: </li></ul></ul><ul><ul><ul><li>def number = 2 </li></ul></ul></ul><ul><ul><ul><li>assert (number + 2) == 4 </li></ul></ul></ul>
  4. 4. GroovyTestCase <ul><li>class SimpleUnitTest extends GroovyTestCase { </li></ul><ul><li>void testSimple() { </li></ul><ul><li>def integerList = [1, 2, 3] </li></ul><ul><li>assertEquals 2, integerList[1] </li></ul><ul><li>assertEquals 6, integerList[0] + integerList[1] + integerList[2] </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  5. 5. GroovyTestCase: testing for exceptions <ul><li>class ClassToTest { </li></ul><ul><li>def methodWhichThrowsException() { </li></ul><ul><li>// Doing some work... </li></ul><ul><li>throw new NumberFormatException(&quot;Warning!&quot;) </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>void testSimple() { </li></ul><ul><li>def objectToTest = new ClassToTest() </li></ul><ul><li>shouldFail(NumberFormatException) { </li></ul><ul><li>objectToTest.methodWhichThrowsException() </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  6. 6. Mocks and Stubs <ul><li>- Mocks and stubs are used to substitute real collaborators of the tested class </li></ul><ul><li>- With mocks and stubs you can unit test your code in isolation without depend form external code </li></ul><ul><li>- stubs have weak expectations: verify state of mocked objects </li></ul><ul><li>- mocks have strong expectations: verify state and behaviour of mocked objects </li></ul>
  7. 7. The Java way <ul><li>- Easymock, jMock, jMockit, Mockito... </li></ul><ul><li>public void testGetPrice() { </li></ul><ul><li>CurChange mockedDependency = createMock(CurChange.class); </li></ul><ul><li>expect(mockedDependency.getPriceByEUR(EUR)).andReturn(new BigDecimal(100)); </li></ul><ul><li>replay(mockedDependency); </li></ul><ul><li>BigDecimal price = systemUnderTest.getPrice(EUR); </li></ul><ul><li>assertNotNull(price); </li></ul><ul><li>verify(mockedDependency); </li></ul><ul><li>} </li></ul>
  8. 8. The Groovy way <ul><li>Groovy dynamic nature allows easy mocks implementation </li></ul><ul><li>- Mock using mockFor and stubFor </li></ul><ul><li>- Mock using Categories </li></ul><ul><li>- Mock using ExpandoMetaClass </li></ul><ul><li>- Mock using Expandos and Maps </li></ul>
  9. 9. Mock using mockFor and stubFor <ul><li>- Inspired by easyMock, with same power and semantic </li></ul><ul><li>- Similar to Java </li></ul><ul><li>- Can be used everywhere a mock is needed </li></ul><ul><li>- You define expectations and verify them </li></ul><ul><li>- Mock Groovy and Java Collaborators </li></ul><ul><li>- Behavior specified via Closures, allowing static or calculated return values, throwing exceptions, asserting argument values... </li></ul><ul><li>- Not dependent on any external mock library </li></ul>
  10. 10. StubFor and mockFor <ul><li>def save = { </li></ul><ul><li>try { </li></ul><ul><li>def file = new File(baseDir, </li></ul><ul><li>file.text = params.text </li></ul><ul><li>render &quot;success&quot; </li></ul><ul><li>} catch (Exception e) { </li></ul><ul><li>render &quot;exception ${e.message}&quot; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  11. 11. stubFor <ul><li>void testSave() { </li></ul><ul><li>def testObj = new ClassToTest() </li></ul><ul><li>def fileMock = new StubFor( </li></ul><ul><li>def resultText </li></ul><ul><li>fileMock.demand.setText() { resultText = it } </li></ul><ul><li>fileMock.demand.close {} </li></ul><ul><li>fileMock.use { </li></ul><ul><li> </li></ul><ul><li>} </li></ul><ul><li>assertEquals &quot;Qui va il contenuto del file&quot; , resultText </li></ul><ul><li>} </li></ul>
  12. 12. mockFor <ul><li>def save = { </li></ul><ul><li>def params = ['baseDir': '.', 'id': 'NuovoFile', 'text': 'Qui va il contenuto del file'] </li></ul><ul><li>try { </li></ul><ul><li>def file = new File(params.baseDir, </li></ul><ul><li>file.text = params.text </li></ul><ul><li>file.text = &quot;Qui aggiungo testo&quot; </li></ul><ul><li>file.close() </li></ul><ul><li>} catch (Exception e) { </li></ul><ul><li>log &quot;exception ${e.message}&quot; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  13. 13. mockFor <ul><li>void testSave() { </li></ul><ul><li>def testObj = new ClassToTest() </li></ul><ul><li>def fileMock = new MockFor( </li></ul><ul><li>def resultText1, resultText2 </li></ul><ul><li>fileMock.demand.setText() { resultText1 = it } </li></ul><ul><li>fileMock.demand.setText() { resultText2 = it } </li></ul><ul><li>fileMock.demand.close(1..1) {} </li></ul><ul><li>fileMock.use { </li></ul><ul><li>testObj.saveForMock() </li></ul><ul><li>} </li></ul><ul><li>assertEquals &quot;Qui va il contenuto del file&quot; , resultText1 </li></ul><ul><li>assertEquals &quot;Qui aggiungo testo&quot; , resultText2 </li></ul><ul><li>} </li></ul>
  14. 14. Mocking using Categories <ul><li>What are Categories ? A MOP method injection technique </li></ul><ul><li>class StringStrangeFormatUtil { </li></ul><ul><li>def static specialFormat(String self) { </li></ul><ul><li>if (self.size() < 10) { </li></ul><ul><li>return &quot;***${self}***&quot; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>use(StringStrangeFormatUtil) { </li></ul><ul><li>println &quot;ciao&quot;.specialFormat() </li></ul><ul><li>} </li></ul>
  15. 15. Mocking using Categories <ul><li>def methodForMockUsingCategoriesOrMetaclass() { </li></ul><ul><li>int value = collaboratorMethod() * 3 </li></ul><ul><li>return value </li></ul><ul><li>} </li></ul><ul><li>def collaboratorMethod() { </li></ul><ul><li>// Attendere prego... </li></ul><ul><li>// Please Wait... </li></ul><ul><li>return 10 </li></ul><ul><li>} </li></ul>
  16. 16. Mocking using Categories <ul><li>class TestMockUsingCategories extends GroovyTestCase { </li></ul><ul><li>void testMethodForMockUsingCategories() { </li></ul><ul><li>def testObj = new ClassToTest() </li></ul><ul><li>use(MockHelper) { </li></ul><ul><li>def result = testObj.methodForMockUsingCategoriesOrMetaclass() </li></ul><ul><li> assertEquals 399, result </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>class MockHelper { </li></ul><ul><li>def static collaboratorMethod(ClassToTest self) { 133 } </li></ul><ul><li>} </li></ul>
  17. 17. Mocking using ExpandoMetaClass <ul><li>void testMethodForMockUsingCategoriesOrMetaclass() { </li></ul><ul><li>def emc = new ExpandoMetaClass(ClassToTest) </li></ul><ul><li>emc.collaboratorMethod = { -> 133 } </li></ul><ul><li>emc.initialize() </li></ul><ul><li>def testObj = new ClassToTest() </li></ul><ul><li>testObj.metaClass = emc </li></ul><ul><li>def result = testObj.methodForMockUsingCategoriesOrMetaclass() </li></ul><ul><li>assertEquals 399, result </li></ul><ul><li>} </li></ul>
  18. 18. Mocking using Expandos <ul><li>def saveFile(file) { </li></ul><ul><ul><li>file.write &quot;Testo del file.&quot; </li></ul></ul><ul><li>} </li></ul><ul><li>void testSaveFile() { </li></ul><ul><li>def fileMock = new Expando(text: &quot;, write: {text = &quot;Testo dinamico dell'Expando&quot; }) </li></ul><ul><li>def testObj = new ClassToTest() </li></ul><ul><li>testObj.saveFile(fileMock) </li></ul><ul><li>assertEquals &quot;Testo dinamico dell'Expando&quot; , fileMock.text </li></ul><ul><li>} </li></ul>
  19. 19. Mocking using Maps <ul><li>void testSaveFile() { </li></ul><ul><li>def text = '' </li></ul><ul><li>def fileMock = [write : { text = &quot;Testo dinamico della mappa&quot; }] </li></ul><ul><li>def testObj = new ClassToTest() </li></ul><ul><li>testObj.saveFile(fileMock) </li></ul><ul><li>assertEquals &quot;Testo dinamico della mappa&quot; , text </li></ul><ul><li>} </li></ul>
  20. 20. Testing Grails Actions <ul><li>- Integration test: Grails uses a HSQL DB and injects environment objects (session, controllers...) </li></ul><ul><li>def team1, team2, team3, team4 </li></ul><ul><li>void setUp() { </li></ul><ul><li>team1 = new Team(name: 'Varese', championship: 'Serie C2', city: 'Varese', supporters: 1000, foundationYear: 1910).save() </li></ul><ul><li>.... </li></ul><ul><li>} </li></ul><ul><li>void tearDown() { </li></ul><ul><li>Team.list()*.delete() </li></ul>
  21. 21. Testing Grails Action <ul><li>void testSearch() { </li></ul><ul><li>def tc = new TeamController() </li></ul><ul><li>tc.params.championship = &quot;Serie C2 &quot; </li></ul><ul><li> </li></ul><ul><li>assertEquals &quot;/team/list&quot;, tc.modelAndView.viewName </li></ul><ul><li>assertEquals 1, tc.modelAndView.model.teamCount </li></ul><ul><li>assertTrue tc.modelAndView.model.teamList.contains(team1) </li></ul><ul><li>} </li></ul>
  22. 22. Conclusions <ul><li>- Some techniques (like Expandos or Categories) are useful when testing Groovy classes </li></ul><ul><li>- Mocking using maps is useful when testing Java classes but you have to pass the mocked object to the Class Under Test </li></ul><ul><li>- mockFor and stubFor are very powerful and are used as an alternative to frameworks like easymock, jMock... </li></ul><ul><li>- more frameworks are coming (Gmock) </li></ul><ul><li>- The future: Behavior driven development (BDD) ? easyB... </li></ul>
  23. 23. Reference <ul><li>- Groovy in Action (D. Konig, A. Glover, P. King, G. Laforge, J. Skeet) – Manning </li></ul><ul><li>- Programming Groovy – Dynamic productivity for the Java developer (Venkat Subramaniam) – Pragmatic Programmera </li></ul><ul><li>- </li></ul>