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