I'm upgrading an inherited Grails 2 app to 3.3.10. We have controller methods that rely on Domain class validation to control logic flow, but we can't get DomainClass validation to work in ControllerUnitTests when running in Grails 3
For example,
Gift
and RecipientAddress
are DomainClasses and RecipientAddress.hasErrors()
is used to validate against the RecipientAddress constraints.
def confirmAddress() {
Gift gift = Gift.get(params.giftId)
if (!gift) {
render(view: "index", model: [invalid: true])
return
}
recipientAddress = recipientAddressService.storeAddressInformation(params, gift)
if (recipientAddress.hasErrors()) {
render(view: "index", model: getAddressErrorModel(gift, recipientAddress))
return;
} else {
return [
recipientAddress : recipientAddress,
gift : gift
]
}
}
In the following test, when I debug the controller method it does everything expected but recipientAddress.hasErrors()
always returns true
and the test fails.
ie:
@Transactional
class GiftDetailsControllerTest extends Specification implements ControllerUnitTest<GiftDetailsController> {
@Shared
@AutoCleanup
SimpleMapDatastore dataStore = new SimpleMapDatastore([ConnectionSource.DEFAULT, "reporting"],
RecipientAddress, Gift)
def setup() {
controller.recipientAddressService = Mock(RecipientAddressService)
}
void "test RecipientAddress Bad PhoneNumber"() {
given:
RecipientAddress recipientAddress = new RecipientAddress(
phone: '123-456-789'
)
UnitTestDataFactory dataFactory = UnitTestDataFactory.getDataFactory()
Gift gift = dataFactory.getMockGift()
gift.save()
params.giftId = gift.id
when:
recipientAddress.validate()
controller.confirmAddress()
then:
recipientAddress.hasErrors()
recipientAddress.getErrors().getFieldError('phone')
1 * controller.recipientAddressService.storeAddressInformation(params, gift) >> recipientAddress
view == '/giftDetails/index'
}
}
Implementing DataTest
ie: ...implements ControllerUnitTest<GiftDetailsController>, DataTest {
fixes the DomainClass validation, but breaks the controllers ability to get the saved Gift.
Is there a way get DomainClass validation working in a ControllerUnit test?
Implemented DataTest with mockDomains and had to remove the custom dataStore.
@Transactional
class GiftDetailsControllerTest extends Specification implements ControllerUnitTest<GiftDetailsController>, DataTest {
// @Shared
// @AutoCleanup
// SimpleMapDatastore dataStore = new SimpleMapDatastore([ConnectionSource.DEFAULT, "reporting"], RecipientAddress, Gift)
void setupSpec() {
mockDomains RecipientAddress, Gift
}
....
Is there a way get DomainClass validation working in a ControllerUnit test?
Yes.
You probably want something like this...
class GiftDetailsControllerTest extends Specification implements ControllerUnitTest<GiftDetailsController>, DataTest {
Class[] getDomainClassesToMock() {
[Gift]
}
// ...
}