Tuesday, February 10, 2009

Grails combining integration and unit testing

Yesterday I faced the situation when in integration test I needed some logic to be mocked and to be executed in particular way. Therefore I asked a question about possibility of combining integration and unit testing approaches. In someone is interested - please review mentioned situation in details. Do not forget that is based on Grails Testing Plugin, so if You are new to it please review some of my previous posts.

I have FileService which has methods for saving/retrieving/deleting files in local file system. Files are distinguished by guid, and full path to the file is generated using storage root property plus mentioned guid. Storage root property is hard coded into the service (I know that is not the best solution but quiet comfortable for me). Described logic is listed below:
class FileService {

// File system's storage root. Hardcoded.
String storageRoot = "C:\\"

def retrieveFullPath(String guid) {
"${storageRoot}\\${guid}.pdf"
}

// Some other methods for
// saving/retrieving/deleting files.


}

Also I have other service called Project Service in which File Service is dynamically injected using Spring. It uses its retrieveFullPath method. Let's look more concrete:
class ProjectService {

def fileService

def retrieveProject(String guid) {
// Some logic.
def filePath = fileService.retrieveFullPath(guid)
// Some logic.
}

// Some other methods.
}

Everything looking good and I decided to write simple integration test. But faced with the first question: in my test I need test file to be stored somewhere in the test folder of the application. But when I will use it's guid, file service will retrieve full path according to storage root property and that path will be invalid and exception will be thrown. Therefore I decided to mock mentioned logic in order to retrieve real file which exists under test folder. Let's have a look at the test:

class ProjectServiceTests extends GrailsUnitTestCase {

def projectService

void setUp() {
// Do not forget to call super method at first.
super.setUp()

// Initialise the service.
// There is no dynamic injection.

projectService = new ProjectService()
}

void testRetrieveProject() {
// Loading file for test folder
// using Spring's ClassPathResource class.

def fileName =
new ClassPathResource("test/testfile.pdf")
.getFile().getPath()


// Mocking file service not to use its storage root
// and to return needed file path.
// In this case file service will return
// real path to the file in Your file system.

def fileServiceMock = mockFor(FileService)
fileServiceMock.demand.retrieveFullPath {
String guid ->
return fileName
}

// Creating a file service mock
// in project service.

projectService.fileService =
(FileService) fileServiceMock.createMock()

// Calling the target method.
projectService.retrieveProject("testfile")

// Some assertions.
}

}

That's all. In listed integration test we combined some approaches from unit testing. Hope someone found it interesting.

No comments:

Post a Comment