Saturday, February 7, 2009

Unit testing: testing service in 3 different ways (part II)

In part I we got acquainted with unit testing of services based on ExpandoMetaClass approach. In this part we will look on a method based on Groovy Mocks. Groovy has excellent built-in support for a range of mocking alternatives. Let's rewrite test from the previous post in order to use Groovy Mocks.

class DocumentServiceTests extends GroovyTestCase {

def documentService

void setUp() {

// Initialize the service class,
// there is no dynamic injection.

documentService = new DocumentService()
}

void testSaveDocumentSuccess() {
// Create the Mock support
// for Document class.

def documentMocker = new MockFor(Document)


// Demand the validate method exactly once,
// and programming it to return true.

documentMocker.demand.validate {
return true
}


// Demand the save method exactly once,
// and programming it to return true.

documentMocker.demand.save {
return true
}

// Start using the Mock.
documentMocker.use {
documentService.saveDocument(
new Document(
name: "Document name",
description: "Document description",
lastModifiedTime: new Date(),
creationTime: new Date(),
revisionCount: 1L,
owner: new User()))
}
}

void testSaveDocumentFailure() {

// Create the Mock support
// for Document class.

def documentMocker = new MockFor(Document)


// Demand the validate method exactly once,
// and programming it to return false.

documentMocker.demand.validate {
return false
}

// Start using the Mock.
documentMocker.use {
// Validation will fail.
// Expecting exception to be thrown.

shouldFail(InvalidDocumentException) {
documentService.saveDocument(
new Document(
name: "Document name",
description: "Document description",
lastModifiedTime: new Date(),
creationTime: new Date(),
revisionCount: 1L))
}
}
}

void testRetrieveDocumentByIdAndOwnerSuccess() {

// Create the Mock support
// for Document class.

def documentMocker = new MockFor(Document)


// Demand the findByIdAndOwner method exactly once,
// and programming it to return appropriate document.

documentMocker.demand.findByIdAndOwner {
Long id, User owner ->
return new Document(
id: id,
name: "Document name",
description: "Document description",
lastModifiedTime: new Date(),
creationTime: new Date(),
revisionCount: 1L,
owner: owner)
}


// Demand the getName method exactly once,
// and programming it to return appropriate name.
// Needed for assertion.

documentMocker.demand.getName {
return "Document name"
}


// Demand the getDescription method exactly once,
// and programming it to return appropriate name.
// Needed for assertion.

documentMocker.demand.getDescription {
return "Document description"
}


// Demand the getRevisionCount method exactly once,
// and programming it to return appropriate name.
// Needed for assertion.

documentMocker.demand.getRevisionCount {
return 1L
}

// Start using the Mock.
documentMocker.use {
def foundDocument =
documentService.retrieveDocumentByIdAndOwner(
1L, new User())

assertNotNull foundDocument
assert "Document name" == foundDocument.name
assert "Document description" == foundDocument.description
assert 1 == foundDocument.revisionCount
}
}

void testRetrieveDocumentFailure() {

// Create the Mock support
// for Document class.

def documentMocker = new MockFor(Document)


// Demand the findByIdAndOwner method exactly once,
// and programming it to return NULL.

documentMocker.demand.findByIdAndOwner { Long id, User owner ->
return null
}

// Start using the Mock.
documentMocker.use {
// Document will not be found.
// Exception will be thrown.

shouldFail(DocumentNotFoundException) {
documentService.retrieveDocumentByIdAndOwner(
1L, new User())
}
}
}

}

Groovy Mocks have a lot of powerful features, especially You can mock few calls of service method, You can mock not only a tested service but also an injected service, etc. For more detailed information check resources listed below:
  1. Using MockFor and StubFor
  2. Mocking Static Methods using Groovy
In the next post we will rewrite mentioned test using Testing plugin.

No comments:

Post a Comment