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.