Table of contents
  1. Config in test
    1. Modify config
    2. Get at application
    3. Use db in memory to run tests
    4. Mocking service and then method call, setting dummy data for the return(put in test method)
    5. Mocking Service used in a service you are testing(put at beginning of the test class)
    6. Mocking Method in service you are testing
    7. Mocking method in domain
    8. Using Test Data from BuildTest plugin
      1. Snippet from spock test
        1. Different ways to build
  2. Configurations
    1. Checking validity of constraints
    2. check if method was called for another service
    3. check if method was called for same service
    4. create an exception
    5. catch exception
    6. modify config during/for test
    7. create a custom manager for a test
    8. Mocking hibernate used to test methods using where queriers / detached criteria / criteria builder
    9. Mock return value for service method used in the service you are testing
    10. Mock a static method call from a domain
  3. Test Snippets
    1. Test Rest
      1. Grails3
      2. Grails4
        1. Ex. Integrations test for controller




Config in test

Modify config


Holders.grailsApplication.config.outlook.clientId = "GUUNAR5"

Get at application


grails.util.Holders.grailsApplication.domainClasses.find { it.shortName == 'User' }

Use db in memory to run tests

@shared Sql sql = Sql.newInstance("jdbc: h2 : mem: ", "org.h2.Driver")

Mocking service and then method call, setting dummy data for the return(put in test method)

controller.openweathermapService = Mock(OpenweathermapService)

controller.openweathermapService.currentWeatherByGeoID(_) >> currentWeather

Mocking Service used in a service you are testing(put at beginning of the test class)


Closure doWithSpring() {
    { ->
        assessmentOrderService AssessmentOrderService
    }
}

AssessmentOrderService assessmentOrderService

Mocking Method in service you are testing

 @Shared
GroupCompareJoinUserGroupService groupCompareJoinUserGroupService

setupSpec() {
    mockDomain GroupCompareJoinUserGroup

}

def "some test"() {
    service.groupCompareJoinUserGroupService = Mock(GroupCompareJoinUserGroupService)
    service.groupCompareJoinUserGroupService.fetchAssociatedAssessments(_ as GroupCompare, true) >> { groupCompare, removeRelationships -> groupCompareJoinUserGroupService.fetchAssociatedAssessments(groupCompare, true) }

}

Mocking method in domain

[service / controller / domain].metaclass.'static'.[method] = { [arguments] -> [returnValue] }

Using Test Data from BuildTest plugin

Snippet from spock test

Pluggin for using test data builder
BuildTestData

import grails.buildtestdata.mixin.Build

use- implements BuildDomanTest< > instead of DomainUnitTest < >


@Build([Job, Tag, Type, Publisher])
class StatisticsServiceSpec extends Specification implements AutowiredTest, DataTest, BuildDataTest, ServiceUnitTest<StatisticsService>, GrailsWebUnitTest {

    def setupSpec() {
        mockDomain Job
        mockDomain Tag
        mockDomain Type
        mockDomain Publisher
    }

    def setup() {
    }

    def cleanup() {
    }

    void "get top publishers when we don't have nothing in our system"() {
        given: "when we don't have any job published"

        when: "we get top publishers"
        def publishers = service.getTopPublishers()
        then: "we will see 0 publishers"
        publishers.size() == 0
    }

    void "get top publishers when we have multiple jobs published by the same publisher"() {
        given: "when we have one 2 jobs published by the same publisher"
        def tag = Tag.build()
        def type = Type.build()
        def publisher = Publisher.build()
        Job.build(publisher: publisher, type: type, tags: [tag])
        Job.build(publisher: publisher, type: type, tags: [tag])

        when: "we get top publishers"
        def publishers = service.getTopPublishers()
        def pair = publishers.find { key, value -> key.name.equals('http://publisher.name') }

        then: "we will see 2 publishers"
        publishers.size() == 1
        pair?.value == 2
    }

}

  • config file test/resources/TestDataConfig
import com.talentbank.core.ClientSetup

import java.util.concurrent.ThreadLocalRandom

//config file for test data plugin
testDataConfig {
    sampleData {
        unitAdditionalBuild = ['com.talentbank.core.assessmentOrder.AssessmentOrder': [com.talentbank.core.ClientSetup]]

        'com.talentbank.core.ClientSetup' {
            //work around for unique constraints
            def i = 55
            clientId = { -> ThreadLocalRandom.current().nextLong(100000) }
            companyCode = { -> "company${i}" }
            clientName = { -> "clientName${i++}" }
        }

        'com.talentbank.core.User' {
            def i = 55
            username = { -> "email${i++}@mailinator.com" }
            email = { -> "email${i}@mailinator.com" }
        }

        'com.talentbank.core.assessmentOrder.AssessmentOrder' {
            clientSetup = { -> ClientSetup.build() }
        }
    }
}

Different ways to build


def intviewModel = TestData.build(InterviewModel)
def y = InterviewModel.build(source: Source.TBSIX)
def z = build(InterviewModel, source: Source.TBSIX)

Configurations

Checking validity of constraints

!newScheduledInterview2.validate(['scheduledBy', 'scheduledDate'])
!newScheduledInterview2.save(flush: true)
newScheduledInterview2.errors['scheduledDate']?.code == 'unique'

check if method was called for another service

def called = false
service.notifierService = Mock(NotifierService)
service.notifierService.sendPostMarkEmail(_ as PostMarkEmail, _) >> { it -> called = true }

check if method was called for same service

service.metaClass.sendReminderEmail = { assessmentOrderId, templateId, sender, newTemplateBody, jobId -> calls++ }

create an exception

//create expando
def testDelete = new Expando()

// add exception to method call
def exception = { new Exception("TEST") }
testDelete.delete = { throw exception }

// add class as return for a method
service.metaClass.method_to_throw_exception = { testDelete }

//example in CalenderServiceSpec.groovy / “test delete exception”
//or
service.metaClass.yourMethod >> { throw exception }

catch exception

def response = thrown(GraphServiceException)

modify config during/for test

   Holders.grailsApplication.config.outlook.clientId = "GUUNAR5"

create a custom manager for a test


def managerMap = [:]
RoleGroup.findAll().each {
    def myUser = User.build(clientSetupId: 1, email:
            "${it.name}@mailinator.com", username: "${it.name}@mailinator.com")
    UserRoleGroup.build(user: myUser, roleGroup: it)
    def tokenAuthentication = new TokenAuthentication(decodedJwt(myUser), myUser)
    tokenAuthentication.details = myUser
    authMap[(it.name)] = tokenAuthentication
    managerMap[(myUser.id)] = it.name ==~ /testManager.*/ ? [1, 2, 3] : []
}
service.userService = Mock(UserService)
service.userService.fetchDirectReportIds(_) >> { it ->
    managerMap.get(it[0])
}

Mocking hibernate used to test methods using where queriers / detached criteria / criteria builder

 @Shared
InterviewModelService interviewModelService

@Shared
HibernateDatastore hibernateDatastore

@Shared
PlatformTransactionManager transactionManager

Map configuration = [
        'hibernate.hbm2ddl.auto'              : 'create-drop',
        'dataSource.url'                      : 'jdbc:h2:mem:myDB',
        'hibernate.cache.region.factory_class': 'org.hibernate.cache.ehcache.EhCacheRegionFactory'
]
hibernateDatastore = new HibernateDatastore(configuration, CatalogDetail)
transactionManager = hibernateDatastore.getTransactionManager()
catalogDetailService = hibernateDatastore.getService(CatalogDetailService)


//Set tests to rollback

@Rollback
void "test criteria builder for getting interview models should return all"() {
    //test
}

Mock return value for service method used in the service you are testing

service.springSecurityService = [authentication: [details: currentUser]]

Mock a static method call from a domain

ClientSetup.metaClass.static.fetchSecurityGroupLabelsByClientSetupId = { Long id, String en -> [secGroupNameLabel: 'secGroupNameLabel', secGroupCodeLabel: 'secGroupCodeLabel'] }

Test Snippets

Test Rest

Grails3

Controller

Grails4

Ex. Integrations test for controller

package musicandcars

import grails.testing.mixin.integration.Integration
import grails.testing.spock.OnceBefore
import io.micronaut.core.type.Argument
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus
import io.micronaut.http.MediaType
import io.micronaut.http.client.HttpClient
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Stepwise

@Integration
@Stepwise
class CarFunctionalSpec extends Specification {

    @Shared
    HttpClient client

    @OnceBefore
    void init() {
        String baseUrl = "http://localhost:$serverPort"
        this.client = HttpClient.create(baseUrl.toURL())
    }

    void "test that no cars exist"() {
        when:
        HttpResponse<List<Map>> resp = client.toBlocking().exchange(HttpRequest.GET("/automobiles"), Argument.of(List, Map))

        then:
        resp.status == HttpStatus.OK
        resp.body().size() == 0
        resp.contentType.get().extension == MediaType.EXTENSION_JSON
    }
}