You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by ma...@apache.org on 2026/01/28 12:37:12 UTC

(grails-core) 01/01: test: suggestions for pr 15348

This is an automated email from the ASF dual-hosted git repository.

matrei pushed a commit to branch test/expand-integration-test-coverage-suggestions
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 8712675e4cfcb2f32281ece4aa65c846c0e1c446
Author: Mattias Reichel <ma...@gmail.com>
AuthorDate: Wed Jan 28 13:36:14 2026 +0100

    test: suggestions for pr 15348
---
 .../async/AsyncTestController.groovy               |  37 +-
 .../functionaltests/i18n/I18nTestController.groovy |   5 +-
 .../ConditionalMatchInterceptor.groovy             |   8 +-
 .../interceptors/FirstInterceptor.groovy           |   6 +-
 .../interceptors/InterceptorTestController.groovy  |  16 +-
 .../interceptors/SecondInterceptor.groovy          |   6 +-
 .../interceptors/SessionInterceptor.groovy         |   4 +-
 .../interceptors/ThirdInterceptor.groovy           |   6 +-
 .../interceptors/TimingInterceptor.groovy          |   4 +-
 .../springevents/SpringEventController.groovy      |   1 -
 .../taglib/TagLibTestController.groovy             |   4 +-
 .../domain/functionaltests/binding/Employee.groovy |   1 -
 .../functionaltests/constraints/PaymentInfo.groovy |  10 +-
 .../caching/CacheTestService.groovy                |   5 +-
 .../services/AsyncProcessingService.groovy         |  11 +-
 .../functionaltests/taglib/CustomTagLib.groovy     |   2 +-
 .../functionaltests/async/AsyncPromiseSpec.groovy  |  73 ++--
 .../binding/AdvancedDataBindingSpec.groovy         | 170 +-------
 .../functionaltests/caching/CachingSpec.groovy     | 107 ++---
 .../codecs/SecurityCodecsSpec.groovy               | 163 +------
 .../commanddi/CommandObjectDISpec.groovy           | 181 ++------
 .../constraints/ConstraintValidationSpec.groovy    |   9 +-
 .../contentneg/ContentNegotiationSpec.groovy       | 189 ++------
 .../functionaltests/cors/CorsAdvancedSpec.groovy   |  50 +--
 .../errorhandling/ErrorHandlingSpec.groovy         | 256 +++--------
 .../functionaltests/events/DomainEventsSpec.groovy |  30 +-
 .../fileupload/FileUploadSpec.groovy               |  46 +-
 .../functionaltests/gorm/GormAdvancedSpec.groovy   |  17 +-
 .../i18n/InternationalizationSpec.groovy           | 187 +-------
 .../interceptors/InterceptorOrderingSpec.groovy    | 119 +----
 .../requestresponse/RequestResponseSpec.groovy     |  66 ++-
 .../services/ServiceIntegrationSpec.groovy         |  63 +--
 .../springevents/SpringEventsSpec.groovy           | 166 +++----
 .../functionaltests/taglib/TagLibSpec.groovy       | 477 +++------------------
 .../urlmappings/UrlMappingsSpec.groovy             | 182 ++------
 .../services/pubsub/demo/TotalService.groovy       |   8 +-
 .../groovy/pubsub/demo/AsyncEventsSpec.groovy      |  18 +-
 .../groovy/pubsub/demo/PubSubSpec.groovy           |   9 +-
 .../main/groovy/pubsub/demo/BookSubscriber.groovy  |   9 +-
 .../gorm/grails-app/domain/gorm/Book.groovy        |   2 -
 .../groovy/gorm/FieldsValidationSpec.groovy        | 113 ++---
 .../groovy/gorm/GormCascadeOperationsSpec.groovy   | 124 +++---
 .../groovy/gorm/GormCriteriaQueriesSpec.groovy     |  56 +--
 .../groovy/gorm/GormDataServicesSpec.groovy        | 101 ++---
 .../groovy/gorm/GormEventsSpec.groovy              | 108 ++---
 .../groovy/gorm/ScaffoldingFunctionalSpec.groovy   |  74 ++--
 .../integration-test/groovy/gorm/UserSpec.groovy   |  19 +-
 .../groovy/gorm/ValidationConstraintsSpec.groovy   |  53 +--
 .../groovy/micronaut/MicronautContextSpec.groovy   |  24 +-
 .../groovy/micronaut/MicronautQualifierSpec.groovy |  12 +-
 .../init/scaffoldingfields/Application.groovy      |   3 +
 .../init/scaffoldingfields/BootStrap.groovy        | 153 +++----
 .../scaffoldingfields/CustomTemplatesSpec.groovy   |  20 +-
 .../groovy/scaffoldingfields/FieldTypesSpec.groovy |  10 +-
 .../groovy/scaffoldingfields/PaginationSpec.groovy |  94 ++--
 .../RelationshipsFunctionalSpec.groovy             |  88 ++--
 .../ValidationFunctionalSpec.groovy                |  66 ++-
 .../scaffoldingfields/pages/EmployeePages.groovy   |   3 +
 58 files changed, 1235 insertions(+), 2609 deletions(-)

diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/async/AsyncTestController.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/async/AsyncTestController.groovy
index 763062c3df..bb70cd9ca9 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/async/AsyncTestController.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/async/AsyncTestController.groovy
@@ -19,13 +19,14 @@
 
 package functionaltests.async
 
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicBoolean
+
 import functionaltests.services.AsyncProcessingService
-import grails.converters.JSON
 
-import java.util.concurrent.CompletableFuture
-import java.util.concurrent.TimeUnit
+import grails.converters.JSON
 
-import static grails.async.web.WebPromises.*
+import static grails.async.web.WebPromises.task
 
 /**
  * Controller demonstrating async request handling patterns in Grails.
@@ -125,13 +126,31 @@ class AsyncTestController {
 
         def startTime = System.currentTimeMillis()
         task {
-            sleep delay
-            return 'Completed in time'
-        }.onComplete { result ->
+            def status = 'completed'
+            def message = 'Completed in time'
+            def completed = new AtomicBoolean(false)
+
+            def workThread = Thread.start {
+                sleep(delay)
+                completed.set(true)
+            }
+            workThread.join(timeout)
+
+            if (!completed.get()) {
+                workThread.interrupt()
+                status = 'timeout'
+                message = "Task exceeded timeout of ${timeout} ms"
+            }
+
+            return [
+                    status: status,
+                    message: message
+            ]
+        }.onComplete { taskResult ->
             def elapsed = System.currentTimeMillis() - startTime
             render([
-                status: 'completed',
-                result: result,
+                status: taskResult.status,
+                result: taskResult.message,
                 elapsedMs: elapsed
             ] as JSON)
         }
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/i18n/I18nTestController.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/i18n/I18nTestController.groovy
index 25fc947264..1695314b0d 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/i18n/I18nTestController.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/i18n/I18nTestController.groovy
@@ -19,11 +19,11 @@
 
 package functionaltests.i18n
 
-import grails.converters.JSON
 import org.springframework.context.MessageSource
 import org.springframework.context.i18n.LocaleContextHolder
 import org.springframework.web.servlet.LocaleResolver
-import org.springframework.web.servlet.support.RequestContextUtils
+
+import grails.converters.JSON
 
 /**
  * Controller for testing internationalization (i18n) features.
@@ -32,7 +32,6 @@ import org.springframework.web.servlet.support.RequestContextUtils
 class I18nTestController {
 
     MessageSource messageSource
-    LocaleResolver localeResolver
 
     /**
      * Get a simple message using the current locale.
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ConditionalMatchInterceptor.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ConditionalMatchInterceptor.groovy
index e72f29c009..74d049cac3 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ConditionalMatchInterceptor.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ConditionalMatchInterceptor.groovy
@@ -32,10 +32,10 @@ class ConditionalMatchInterceptor {
     boolean before() {
         // Only add to execution order if 'match' param is 'yes'
         if (params.match == 'yes') {
-            InterceptorTestController.executionOrder << "conditional:before:matched"
+            InterceptorTestController.executionOrder << 'conditional:before:matched'
             request.setAttribute('conditionalMatched', true)
         } else {
-            InterceptorTestController.executionOrder << "conditional:before:notmatched"
+            InterceptorTestController.executionOrder << 'conditional:before:notmatched'
             request.setAttribute('conditionalMatched', false)
         }
         true
@@ -43,9 +43,9 @@ class ConditionalMatchInterceptor {
 
     boolean after() {
         if (params.match == 'yes') {
-            InterceptorTestController.executionOrder << "conditional:after:matched"
+            InterceptorTestController.executionOrder << 'conditional:after:matched'
         } else {
-            InterceptorTestController.executionOrder << "conditional:after:notmatched"
+            InterceptorTestController.executionOrder << 'conditional:after:notmatched'
         }
         true
     }
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/FirstInterceptor.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/FirstInterceptor.groovy
index ddba8a9cef..ad51f493aa 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/FirstInterceptor.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/FirstInterceptor.groovy
@@ -32,17 +32,17 @@ class FirstInterceptor {
     }
 
     boolean before() {
-        InterceptorTestController.executionOrder << "first:before"
+        InterceptorTestController.executionOrder << 'first:before'
         request.setAttribute('firstInterceptorRan', true)
         true
     }
 
     boolean after() {
-        InterceptorTestController.executionOrder << "first:after"
+        InterceptorTestController.executionOrder << 'first:after'
         true
     }
 
     void afterView() {
-        InterceptorTestController.executionOrder << "first:afterView"
+        InterceptorTestController.executionOrder << 'first:afterView'
     }
 }
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/InterceptorTestController.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/InterceptorTestController.groovy
index 3f520f68d9..322b23cd55 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/InterceptorTestController.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/InterceptorTestController.groovy
@@ -33,7 +33,7 @@ class InterceptorTestController {
      * Simple action for testing interceptor before/after execution.
      */
     def index() {
-        executionOrder << "controller:index"
+        executionOrder << 'controller:index'
         render([
             action: 'index',
             executionOrder: new ArrayList<>(executionOrder)
@@ -44,7 +44,7 @@ class InterceptorTestController {
      * Action for testing interceptor ordering.
      */
     def testOrder() {
-        executionOrder << "controller:testOrder"
+        executionOrder << 'controller:testOrder'
         render([
             action: 'testOrder',
             executionOrder: new ArrayList<>(executionOrder)
@@ -55,7 +55,7 @@ class InterceptorTestController {
      * Action that can be blocked by interceptor.
      */
     def blocked() {
-        executionOrder << "controller:blocked"
+        executionOrder << 'controller:blocked'
         render([
             action: 'blocked',
             message: 'This should not be seen if blocked'
@@ -79,7 +79,7 @@ class InterceptorTestController {
      * Action for testing model modification by interceptor.
      */
     def modifyModel() {
-        executionOrder << "controller:modifyModel"
+        executionOrder << 'controller:modifyModel'
         [
             originalValue: 'from controller',
             timestamp: System.currentTimeMillis()
@@ -90,7 +90,7 @@ class InterceptorTestController {
      * Action that returns data to be potentially modified by after interceptor.
      */
     def dataAction() {
-        executionOrder << "controller:dataAction"
+        executionOrder << 'controller:dataAction'
         render([
             data: params.data ?: 'default',
             interceptorModified: false
@@ -142,7 +142,7 @@ class InterceptorTestController {
      * Action for testing afterView interceptor.
      */
     def withView() {
-        executionOrder << "controller:withView"
+        executionOrder << 'controller:withView'
         [message: 'Hello from controller']
     }
 
@@ -152,7 +152,7 @@ class InterceptorTestController {
     def slowAction() {
         def delay = params.int('delay') ?: 100
         Thread.sleep(delay)
-        executionOrder << "controller:slowAction"
+        executionOrder << 'controller:slowAction'
         render([
             action: 'slowAction',
             delay: delay
@@ -163,7 +163,7 @@ class InterceptorTestController {
      * Action for testing conditional interceptor matching.
      */
     def conditionalAction() {
-        executionOrder << "controller:conditionalAction"
+        executionOrder << 'controller:conditionalAction'
         render([
             action: 'conditionalAction',
             param: params.match
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SecondInterceptor.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SecondInterceptor.groovy
index f6c70cfa74..f3cb409386 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SecondInterceptor.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SecondInterceptor.groovy
@@ -32,17 +32,17 @@ class SecondInterceptor {
     }
 
     boolean before() {
-        InterceptorTestController.executionOrder << "second:before"
+        InterceptorTestController.executionOrder << 'second:before'
         request.setAttribute('secondInterceptorRan', true)
         true
     }
 
     boolean after() {
-        InterceptorTestController.executionOrder << "second:after"
+        InterceptorTestController.executionOrder << 'second:after'
         true
     }
 
     void afterView() {
-        InterceptorTestController.executionOrder << "second:afterView"
+        InterceptorTestController.executionOrder << 'second:afterView'
     }
 }
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SessionInterceptor.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SessionInterceptor.groovy
index 129d85ad90..bc20ad8585 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SessionInterceptor.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/SessionInterceptor.groovy
@@ -29,7 +29,7 @@ class SessionInterceptor {
     }
 
     boolean before() {
-        InterceptorTestController.executionOrder << "session:before"
+        InterceptorTestController.executionOrder << 'session:before'
         session.setAttribute('interceptorSessionData', [
             setAt: System.currentTimeMillis(),
             message: 'Session data from interceptor'
@@ -38,7 +38,7 @@ class SessionInterceptor {
     }
 
     boolean after() {
-        InterceptorTestController.executionOrder << "session:after"
+        InterceptorTestController.executionOrder << 'session:after'
         true
     }
 }
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ThirdInterceptor.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ThirdInterceptor.groovy
index 8bdbbaa47e..dd1435796a 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ThirdInterceptor.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/ThirdInterceptor.groovy
@@ -32,17 +32,17 @@ class ThirdInterceptor {
     }
 
     boolean before() {
-        InterceptorTestController.executionOrder << "third:before"
+        InterceptorTestController.executionOrder << 'third:before'
         request.setAttribute('thirdInterceptorRan', true)
         true
     }
 
     boolean after() {
-        InterceptorTestController.executionOrder << "third:after"
+        InterceptorTestController.executionOrder << 'third:after'
         true
     }
 
     void afterView() {
-        InterceptorTestController.executionOrder << "third:afterView"
+        InterceptorTestController.executionOrder << 'third:afterView'
     }
 }
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/TimingInterceptor.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/TimingInterceptor.groovy
index 8a4c2311e4..bd0896255e 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/TimingInterceptor.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/interceptors/TimingInterceptor.groovy
@@ -29,7 +29,7 @@ class TimingInterceptor {
     }
 
     boolean before() {
-        InterceptorTestController.executionOrder << "timing:before"
+        InterceptorTestController.executionOrder << 'timing:before'
         request.setAttribute('requestStartTime', System.currentTimeMillis())
         true
     }
@@ -38,7 +38,7 @@ class TimingInterceptor {
         def startTime = request.getAttribute('requestStartTime') as Long
         def endTime = System.currentTimeMillis()
         def duration = endTime - startTime
-        InterceptorTestController.executionOrder << "timing:after:${duration}ms"
+        InterceptorTestController.executionOrder << "timing:after:${duration}ms".toString()
         // Add header without checking if committed
         response.addHeader('X-Request-Duration', "${duration}")
         true
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/springevents/SpringEventController.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/springevents/SpringEventController.groovy
index e4f6368aa2..860860f674 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/springevents/SpringEventController.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/springevents/SpringEventController.groovy
@@ -20,7 +20,6 @@
 package functionaltests.springevents
 
 import grails.converters.JSON
-import org.springframework.context.ApplicationEventPublisher
 import org.springframework.beans.factory.annotation.Autowired
 
 /**
diff --git a/grails-test-examples/app1/grails-app/controllers/functionaltests/taglib/TagLibTestController.groovy b/grails-test-examples/app1/grails-app/controllers/functionaltests/taglib/TagLibTestController.groovy
index 95c7068fff..9166397a2e 100644
--- a/grails-test-examples/app1/grails-app/controllers/functionaltests/taglib/TagLibTestController.groovy
+++ b/grails-test-examples/app1/grails-app/controllers/functionaltests/taglib/TagLibTestController.groovy
@@ -19,6 +19,8 @@
 
 package functionaltests.taglib
 
+import jakarta.servlet.http.Cookie
+
 /**
  * Controller for testing GSP Tag Libraries.
  * Provides actions that render GSP views using both custom and built-in tags.
@@ -217,7 +219,7 @@ class TagLibTestController {
 
     def testBuiltInCookie() {
         if (params.setCookie) {
-            response.addCookie(new jakarta.servlet.http.Cookie('testCookie', params.setCookie))
+            response.addCookie(new Cookie('testCookie', params.setCookie))
         }
         [cookieName: params.cookieName ?: 'testCookie', defaultValue: params.default ?: 'no cookie']
     }
diff --git a/grails-test-examples/app1/grails-app/domain/functionaltests/binding/Employee.groovy b/grails-test-examples/app1/grails-app/domain/functionaltests/binding/Employee.groovy
index 2fc5e27d96..4238823a12 100644
--- a/grails-test-examples/app1/grails-app/domain/functionaltests/binding/Employee.groovy
+++ b/grails-test-examples/app1/grails-app/domain/functionaltests/binding/Employee.groovy
@@ -19,7 +19,6 @@
 
 package functionaltests.binding
 
-import grails.databinding.BindInitializer
 import grails.databinding.BindUsing
 import grails.databinding.BindingFormat
 
diff --git a/grails-test-examples/app1/grails-app/domain/functionaltests/constraints/PaymentInfo.groovy b/grails-test-examples/app1/grails-app/domain/functionaltests/constraints/PaymentInfo.groovy
index c3ac70396a..4474f2c437 100644
--- a/grails-test-examples/app1/grails-app/domain/functionaltests/constraints/PaymentInfo.groovy
+++ b/grails-test-examples/app1/grails-app/domain/functionaltests/constraints/PaymentInfo.groovy
@@ -19,6 +19,8 @@
 
 package functionaltests.constraints
 
+import java.math.RoundingMode
+
 /**
  * Domain class demonstrating financial constraints:
  * - Credit card validation
@@ -123,8 +125,8 @@ class PaymentInfo {
         // Tax amount must match calculation
         taxAmount nullable: true, scale: 2, validator: { val, obj ->
             if (val == null || obj.amount == null || obj.taxRate == null) return true
-            def expectedTax = (obj.amount * obj.taxRate / 100).setScale(2, BigDecimal.ROUND_HALF_UP)
-            if (val.setScale(2, BigDecimal.ROUND_HALF_UP) != expectedTax) {
+            def expectedTax = (obj.amount * obj.taxRate / 100).setScale(2, RoundingMode.HALF_UP)
+            if (val.setScale(2, RoundingMode.HALF_UP) != expectedTax) {
                 return 'paymentInfo.taxAmount.doesNotMatchCalculation'
             }
         }
@@ -132,8 +134,8 @@ class PaymentInfo {
         // Total must equal amount + tax
         totalAmount scale: 2, validator: { val, obj ->
             if (val == null || obj.amount == null) return true
-            def expectedTotal = obj.amount + (obj.taxAmount ?: 0)
-            if (val.setScale(2, BigDecimal.ROUND_HALF_UP) != expectedTotal.setScale(2, BigDecimal.ROUND_HALF_UP)) {
+            def expectedTotal = obj.amount + (obj.taxAmount ?: 0) as BigDecimal
+            if (val.setScale(2, RoundingMode.HALF_UP) != expectedTotal.setScale(2, RoundingMode.HALF_UP)) {
                 return 'paymentInfo.totalAmount.doesNotMatchSum'
             }
         }
diff --git a/grails-test-examples/app1/grails-app/services/functionaltests/caching/CacheTestService.groovy b/grails-test-examples/app1/grails-app/services/functionaltests/caching/CacheTestService.groovy
index 841a0c65e7..37736dcbe9 100644
--- a/grails-test-examples/app1/grails-app/services/functionaltests/caching/CacheTestService.groovy
+++ b/grails-test-examples/app1/grails-app/services/functionaltests/caching/CacheTestService.groovy
@@ -19,10 +19,11 @@
 
 package functionaltests.caching
 
-import grails.plugin.cache.Cacheable
+import groovy.transform.CompileStatic
+
 import grails.plugin.cache.CacheEvict
 import grails.plugin.cache.CachePut
-import groovy.transform.CompileStatic
+import grails.plugin.cache.Cacheable
 
 /**
  * Service demonstrating Grails caching features.
diff --git a/grails-test-examples/app1/grails-app/services/functionaltests/services/AsyncProcessingService.groovy b/grails-test-examples/app1/grails-app/services/functionaltests/services/AsyncProcessingService.groovy
index 0da8268862..4eeb3da9e9 100644
--- a/grails-test-examples/app1/grails-app/services/functionaltests/services/AsyncProcessingService.groovy
+++ b/grails-test-examples/app1/grails-app/services/functionaltests/services/AsyncProcessingService.groovy
@@ -16,16 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.services
 
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.Future
+
+import groovy.util.logging.Slf4j
+
 import org.springframework.scheduling.annotation.Async
 import org.springframework.scheduling.annotation.AsyncResult
-import grails.gorm.transactions.Transactional
-import groovy.util.logging.Slf4j
 
-import java.util.concurrent.Future
-import java.util.concurrent.CompletableFuture
+import grails.gorm.transactions.Transactional
 
 /**
  * Service demonstrating async operations.
diff --git a/grails-test-examples/app1/grails-app/taglib/functionaltests/taglib/CustomTagLib.groovy b/grails-test-examples/app1/grails-app/taglib/functionaltests/taglib/CustomTagLib.groovy
index f4a3ee820b..532017139d 100644
--- a/grails-test-examples/app1/grails-app/taglib/functionaltests/taglib/CustomTagLib.groovy
+++ b/grails-test-examples/app1/grails-app/taglib/functionaltests/taglib/CustomTagLib.groovy
@@ -25,7 +25,7 @@ package functionaltests.taglib
  */
 class CustomTagLib {
 
-    static namespace = "custom"
+    static namespace = 'custom'
 
     // Use 'none' encoding for tags that output HTML structure
     // Individual tags can use encodeAsHTML() where needed
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/async/AsyncPromiseSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/async/AsyncPromiseSpec.groovy
index 9d5b028330..43f3feb750 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/async/AsyncPromiseSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/async/AsyncPromiseSpec.groovy
@@ -19,27 +19,26 @@
 
 package functionaltests.async
 
-import functionaltests.Application
-import functionaltests.services.AsyncProcessingService
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
+import java.util.concurrent.TimeUnit
+
 import groovy.json.JsonSlurper
+
+import functionaltests.services.AsyncProcessingService
 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.Specification
 import spock.lang.Shared
+import spock.lang.Specification
+import spock.lang.Unroll
 
-import java.util.concurrent.TimeUnit
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for async/promise functionality in Grails.
  * Tests various async patterns including tasks, promises, chaining, and error handling.
  */
-@Integration(applicationClass = Application)
-@Rollback
+@Integration
 class AsyncPromiseSpec extends Specification {
 
     @Shared
@@ -48,18 +47,18 @@ class AsyncPromiseSpec extends Specification {
     AsyncProcessingService asyncProcessingService
 
     def setup() {
-        client = HttpClient.create(new URL("http://localhost:${serverPort}"))
+        client = client ?: HttpClient.create(new URL("http://localhost:${serverPort}"))
     }
 
-    def cleanup() {
-        client?.close()
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Basic Async Task Tests ==========
 
     def "simple async task completes successfully"() {
         when: "calling simple task endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/asyncTest/simpleTask'),
             String
         )
@@ -76,7 +75,7 @@ class AsyncPromiseSpec extends Specification {
         def value = 7
 
         when: "calling compute endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/computeTask?value=${value}"),
             String
         )
@@ -90,7 +89,7 @@ class AsyncPromiseSpec extends Specification {
 
     def "parallel tasks complete and return all results"() {
         when: "calling parallel tasks endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/asyncTest/parallelTasks'),
             String
         )
@@ -110,7 +109,7 @@ class AsyncPromiseSpec extends Specification {
         def input = 'hello'
 
         when: "calling chained endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/chainedTasks?input=${input}"),
             String
         )
@@ -127,7 +126,7 @@ class AsyncPromiseSpec extends Specification {
 
     def "async task handles success without error"() {
         when: "calling task that should succeed"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/asyncTest/taskWithError?fail=false'),
             String
         )
@@ -139,19 +138,25 @@ class AsyncPromiseSpec extends Specification {
         json.result == 'Success'
     }
 
-    def "async task with timeout completes within time limit"() {
+    @Unroll
+    def "async task with timeout completes within time limit"(int delay, int timeout, int elapsedMin, String status, String result) {
         when: "calling task with reasonable timeout"
-        HttpResponse<String> response = client.toBlocking().exchange(
-            HttpRequest.GET('/asyncTest/taskWithTimeout?delay=100&timeout=500'),
+        def response = client.toBlocking().exchange(
+            HttpRequest.GET("/asyncTest/taskWithTimeout?delay=$delay&timeout=$timeout"),
             String
         )
         def json = new JsonSlurper().parseText(response.body())
 
-        then: "task completes successfully"
+        then: "task completes as expected"
         response.status == HttpStatus.OK
-        json.status == 'completed'
-        json.result == 'Completed in time'
-        json.elapsedMs >= 100
+        json.status == status
+        json.result.startsWith(result)
+        json.elapsedMs >= elapsedMin
+
+        where:
+        delay | timeout | elapsedMin | status      | result
+        100   | 500     | 100        | 'completed' | 'Completed in time'
+        100   | 10      | 10         | 'timeout'   | 'Task exceeded timeout of '
     }
 
     // ========== Async Service Tests ==========
@@ -161,7 +166,7 @@ class AsyncPromiseSpec extends Specification {
         def input = 'test'
 
         when: "calling async service endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/useAsyncService?input=${input}"),
             String
         )
@@ -178,7 +183,7 @@ class AsyncPromiseSpec extends Specification {
         def value = 6
 
         when: "calling async calculation endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/asyncCalculation?value=${value}"),
             String
         )
@@ -192,7 +197,7 @@ class AsyncPromiseSpec extends Specification {
 
     def "async batch processing reverses all items"() {
         when: "calling batch endpoint with default items"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/asyncTest/asyncBatch'),
             String
         )
@@ -211,7 +216,7 @@ class AsyncPromiseSpec extends Specification {
         def taskId = 'task-123'
 
         when: "calling long running endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/longRunning?taskId=${taskId}"),
             String
         )
@@ -231,7 +236,7 @@ class AsyncPromiseSpec extends Specification {
         def v2 = 4
 
         when: "calling compose endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/composeFutures?v1=${v1}&v2=${v2}"),
             String
         )
@@ -251,7 +256,7 @@ class AsyncPromiseSpec extends Specification {
         def body = '{"name": "test", "value": "hello"}'
 
         when: "posting to process endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/asyncTest/processRequestData', body)
                 .contentType(MediaType.APPLICATION_JSON),
             String
@@ -267,7 +272,7 @@ class AsyncPromiseSpec extends Specification {
 
     def "multi-stage process reports all stages"() {
         when: "calling multi-stage endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/asyncTest/multiStageProcess'),
             String
         )
@@ -285,7 +290,7 @@ class AsyncPromiseSpec extends Specification {
 
     def "stages execute in correct order"() {
         when: "calling multi-stage endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/asyncTest/multiStageProcess'),
             String
         )
@@ -305,7 +310,7 @@ class AsyncPromiseSpec extends Specification {
         def input = 'grails'
 
         when: "calling with async=true"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/conditionalAsync?async=true&input=${input}"),
             String
         )
@@ -323,7 +328,7 @@ class AsyncPromiseSpec extends Specification {
         def input = 'grails'
 
         when: "calling with async=false"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET("/asyncTest/conditionalAsync?async=false&input=${input}"),
             String
         )
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/binding/AdvancedDataBindingSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/binding/AdvancedDataBindingSpec.groovy
index 7fb441b62c..b3e3777ab9 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/binding/AdvancedDataBindingSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/binding/AdvancedDataBindingSpec.groovy
@@ -16,17 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.binding
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import io.micronaut.http.HttpRequest
-import io.micronaut.http.HttpResponse
 import io.micronaut.http.MediaType
 import io.micronaut.http.client.HttpClient
+import spock.lang.Shared
 import spock.lang.Specification
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Comprehensive integration tests for advanced data binding features.
  * 
@@ -45,19 +44,23 @@ import spock.lang.Specification
  * - Empty string to null conversion
  * - String trimming
  */
-@Integration(applicationClass = Application)
+@Integration
 class AdvancedDataBindingSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Map-Based Binding Tests ==========
 
     def "test basic map-based binding"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindEmployee?firstName=John&lastName=Doe&salary=50000'),
@@ -69,15 +72,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().firstName == 'John'
         response.body().lastName == 'Doe'
         response.body().salary == 50000
-
-        cleanup:
-        client.close()
     }
 
     def "test nested object binding"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindEmployee?firstName=Jane&homeAddress.street=123+Main+St&homeAddress.city=Springfield&homeAddress.state=IL'),
@@ -91,17 +88,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().homeAddress.street == '123 Main St'
         response.body().homeAddress.city == 'Springfield'
         response.body().homeAddress.state == 'IL'
-
-        cleanup:
-        client.close()
     }
 
     // ========== @BindUsing Annotation Tests ==========
 
     def "test @BindUsing annotation lowercases and trims email"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithBindUsing?email=John.Doe%40Example.COM'),
@@ -112,15 +103,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().email == 'john.doe@example.com'
         response.body().originalEmail == 'John.Doe@Example.COM'
-
-        cleanup:
-        client.close()
     }
 
     def "test @BindUsing with mixed case email"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithBindUsing?email=TEST.User%40DOMAIN.org'),
@@ -130,17 +115,11 @@ class AdvancedDataBindingSpec extends Specification {
         then:
         response.status.code == 200
         response.body().email == 'test.user@domain.org'
-
-        cleanup:
-        client.close()
     }
 
     // ========== @BindingFormat Annotation Tests ==========
 
     def "test @BindingFormat for date parsing - MMddyyyy format"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithDateFormat?hireDate=01152020'),
@@ -151,15 +130,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().hireDate == '2020-01-15'
         response.body().hireDateInput == '01152020'
-
-        cleanup:
-        client.close()
     }
 
     def "test @BindingFormat for date parsing - yyyy-MM-dd format"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithDateFormat?birthDate=1990-05-20'),
@@ -170,15 +143,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().birthDate == '1990-05-20'
         response.body().birthDateInput == '1990-05-20'
-
-        cleanup:
-        client.close()
     }
 
     def "test multiple date formats in same request"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithDateFormat?hireDate=03012021&birthDate=1985-12-25'),
@@ -189,17 +156,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().hireDate == '2021-03-01'
         response.body().birthDate == '1985-12-25'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Collection Binding Tests (List) ==========
 
     def "test binding to List collection"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindTeamWithMembers?name=Engineering&members%5B0%5D.name=Alice&members%5B0%5D.role=Lead&members%5B1%5D.name=Bob&members%5B1%5D.role=Developer'),
@@ -214,15 +175,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().members[0].role == 'Lead'
         response.body().members[1].name == 'Bob'
         response.body().members[1].role == 'Developer'
-
-        cleanup:
-        client.close()
     }
 
     def "test binding to List with gaps in indices"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindTeamWithMembers?name=QA&members%5B0%5D.name=Carol&members%5B2%5D.name=Dave'),
@@ -236,17 +191,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().members.size() == 2
         response.body().members.find { it.name == 'Carol' } != null
         response.body().members.find { it.name == 'Dave' } != null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Map Collection Binding Tests ==========
 
     def "test binding to Map collection"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindProjectWithContributors?name=GrailsCore&contributors%5Blead%5D.name=John&contributors%5Blead%5D.expertise=Architecture&contributors%5Bdev%5D.name=Jane&contributors%5Bdev%5D.expertise=Testing'),
@@ -260,17 +209,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().contributors.lead.expertise == 'Architecture'
         response.body().contributors.dev.name == 'Jane'
         response.body().contributors.dev.expertise == 'Testing'
-
-        cleanup:
-        client.close()
     }
 
     // ========== @RequestParameter Annotation Tests ==========
 
     def "test @RequestParameter maps different parameter names"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithRequestParameter?firstName=Robert&lastName=Smith&age=30'),
@@ -282,17 +225,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().givenName == 'Robert'
         response.body().familyName == 'Smith'
         response.body().age == 30
-
-        cleanup:
-        client.close()
     }
 
     // ========== bindData with Include/Exclude Tests ==========
 
     def "test bindData with include - only specified properties bound"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithIncludeExclude?firstName=Test&lastName=User&email=test%40example.com&salary=100000'),
@@ -305,17 +242,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().lastName == 'User'
         response.body().email == null
         response.body().salary == null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Selective Property Binding Tests ==========
 
     def "test selective property binding using subscript operator"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindSelectiveProperties?firstName=Selective&lastName=Test&email=should.not.bind%40test.com&salary=999'),
@@ -328,17 +259,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().lastName == 'Test'
         response.body().email == null
         response.body().salary == null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Direct Data Binder Usage Tests ==========
 
     def "test using grailsWebDataBinder directly"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindUsingDirectBinder?firstName=Direct&lastName=Binder&email=DIRECT%40TEST.COM'),
@@ -351,17 +276,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().lastName == 'Binder'
         // Email should be lowercased due to @BindUsing
         response.body().email == 'direct@test.com'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Command Object Binding Tests ==========
 
     def "test command object binding with validation - valid data"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindCommandObject?firstName=Valid&lastName=User&email=valid%40email.com'),
@@ -375,15 +294,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().email == 'valid@email.com'
         response.body().valid == true
         response.body().errors.isEmpty()
-
-        cleanup:
-        client.close()
     }
 
     def "test command object binding with validation - invalid data"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindCommandObject?firstName=&lastName=&email=invalid-email'),
@@ -395,15 +308,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().valid == false
         response.body().errors.contains('firstName')
         response.body().errors.contains('lastName')
-
-        cleanup:
-        client.close()
     }
 
     def "test nested command object binding"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindNestedCommandObject?name=Contact+Person&address.street=456+Oak+Ave&address.city=Portland'),
@@ -415,17 +322,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().name == 'Contact Person'
         response.body().address.street == '456 Oak Ave'
         response.body().address.city == 'Portland'
-
-        cleanup:
-        client.close()
     }
 
     // ========== JSON Body Binding Tests ==========
 
     def "test JSON body binding to command object"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.POST('/advancedDataBinding/bindJsonBody', [
@@ -442,17 +343,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().lastName == 'JsonLast'
         response.body().email == 'json@test.com'
         response.body().valid == true
-
-        cleanup:
-        client.close()
     }
 
     // ========== Multiple Command Objects Tests ==========
 
     def "test binding multiple command objects"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindMultipleCommandObjects?employee.firstName=Multi&employee.lastName=Test&address.street=789+Pine+Rd&address.city=Seattle'),
@@ -465,17 +360,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().employee.lastName == 'Test'
         response.body().address.street == '789 Pine Rd'
         response.body().address.city == 'Seattle'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Empty String Conversion Tests ==========
 
     def "test empty string converts to null"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindEmptyStrings?firstName=&lastName=HasValue'),
@@ -487,17 +376,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().firstNameIsNull == true
         response.body().lastName == 'HasValue'
         response.body().lastNameIsNull == false
-
-        cleanup:
-        client.close()
     }
 
     // ========== String Trimming Tests ==========
 
     def "test string trimming during binding"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithTrimming?firstName=+++Trimmed+++'),
@@ -508,17 +391,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().firstName == 'Trimmed'
         response.body().firstNameLength == 7
-
-        cleanup:
-        client.close()
     }
 
     // ========== Type Conversion Tests ==========
 
     def "test valid type conversion"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindWithTypeConversion?salary=75000&firstName=TypeTest'),
@@ -529,17 +406,11 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().salary == 75000
         response.body().firstName == 'TypeTest'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Edge Cases ==========
 
     def "test binding with special characters in values"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindEmployee?firstName=O%27Brien&lastName=M%C3%BCller'),
@@ -550,15 +421,9 @@ class AdvancedDataBindingSpec extends Specification {
         response.status.code == 200
         response.body().firstName == "O'Brien"
         response.body().lastName == 'Müller'
-
-        cleanup:
-        client.close()
     }
 
     def "test binding with unicode characters"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindEmployee?firstName=%E6%97%A5%E6%9C%AC%E8%AA%9E'),
@@ -568,15 +433,9 @@ class AdvancedDataBindingSpec extends Specification {
         then:
         response.status.code == 200
         response.body().firstName == '日本語'
-
-        cleanup:
-        client.close()
     }
 
     def "test binding with null parameter values"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/advancedDataBinding/bindEmployee?firstName=TestNull'),
@@ -588,8 +447,5 @@ class AdvancedDataBindingSpec extends Specification {
         response.body().firstName == 'TestNull'
         response.body().lastName == null
         response.body().homeAddress == null
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/caching/CachingSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/caching/CachingSpec.groovy
index 695c4902a6..3ab4ad36c0 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/caching/CachingSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/caching/CachingSpec.groovy
@@ -19,17 +19,19 @@
 
 package functionaltests.caching
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import groovy.json.JsonSlurper
+
 import io.micronaut.http.HttpRequest
-import io.micronaut.http.HttpResponse
 import io.micronaut.http.HttpStatus
 import io.micronaut.http.client.HttpClient
-import org.springframework.beans.factory.annotation.Autowired
 import spock.lang.Narrative
+import spock.lang.Shared
 import spock.lang.Specification
 
+import org.springframework.beans.factory.annotation.Autowired
+
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for Grails caching with @Cacheable, @CacheEvict, @CachePut.
  * 
@@ -40,7 +42,7 @@ import spock.lang.Specification
  * counting method invocations, since @Cacheable proxies prevent method body
  * execution on cache hits.
  */
-@Integration(applicationClass = Application)
+@Integration
 @Narrative('''
 Grails caching provides method-level caching via annotations @Cacheable,
 @CacheEvict, and @CachePut. This allows expensive operations to be cached
@@ -51,17 +53,22 @@ class CachingSpec extends Specification {
     @Autowired
     CacheTestService cacheTestService
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
-    }
+    @Shared
+    HttpClient client
 
     def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+
         // Evict all caches before each test to ensure clean state
         cacheTestService.evictBasicCache()
         cacheTestService.evictAllFromParamCache()
         cacheTestService.evictAllKeyedCache()
     }
 
+    def cleanupSpec() {
+        client.close()
+    }
+
     // ========== Basic @Cacheable Tests - Data Consistency ==========
 
     def "cached method returns same result on subsequent calls"() {
@@ -71,7 +78,7 @@ class CachingSpec extends Specification {
 
         then: "same result is returned (proving caching works)"
         result1 == result2
-        result1.startsWith("Basic data:")
+        result1.startsWith('Basic data:')
     }
 
     def "cached method returns different result after eviction"() {
@@ -86,8 +93,8 @@ class CachingSpec extends Specification {
 
         then: "new result is generated (timestamps differ)"
         result1 != result2
-        result1.startsWith("Basic data:")
-        result2.startsWith("Basic data:")
+        result1.startsWith('Basic data:')
+        result2.startsWith('Basic data:')
     }
 
     def "multiple eviction and fetch cycles work correctly"() {
@@ -208,13 +215,13 @@ class CachingSpec extends Specification {
     def "CachePut updates cache with new value using key closure"() {
         given: "existing cached value for a key"
         def original = cacheTestService.getByKey('mykey')
-        original.startsWith("Value for mykey:")
+        original.startsWith('Value for mykey:')
 
         when: "updating cache with new value"
-        def updated = cacheTestService.updateByKey('mykey', "New value for mykey")
+        def updated = cacheTestService.updateByKey('mykey', 'New value for mykey')
 
         then: "updated value is returned"
-        updated == "New value for mykey"
+        updated == 'New value for mykey'
         
         when: "getting by key again"
         def afterUpdate = cacheTestService.getByKey('mykey')
@@ -225,25 +232,25 @@ class CachingSpec extends Specification {
 
     def "CachePut can be called multiple times"() {
         when: "updating cache multiple times"
-        cacheTestService.updateByKey('testkey', "Value 1")
-        cacheTestService.updateByKey('testkey', "Value 2")
-        def finalValue = cacheTestService.updateByKey('testkey', "Value 3")
+        cacheTestService.updateByKey('testkey', 'Value 1')
+        cacheTestService.updateByKey('testkey', 'Value 2')
+        def finalValue = cacheTestService.updateByKey('testkey', 'Value 3')
 
         then: "last update wins"
-        finalValue == "Value 3"
-        cacheTestService.getByKey('testkey') == "Value 3"
+        finalValue == 'Value 3'
+        cacheTestService.getByKey('testkey') == 'Value 3'
     }
 
     def "CachePut for one key does not affect other keys"() {
         given: "two different cached keys"
-        def key1Original = cacheTestService.getByKey('key1')
+        cacheTestService.getByKey('key1')
         def key2Original = cacheTestService.getByKey('key2')
 
         when: "updating only key1"
-        cacheTestService.updateByKey('key1', "Updated key1")
+        cacheTestService.updateByKey('key1', 'Updated key1')
 
         then: "key1 is updated, key2 is unchanged"
-        cacheTestService.getByKey('key1') == "Updated key1"
+        cacheTestService.getByKey('key1') == 'Updated key1'
         cacheTestService.getByKey('key2') == key2Original
     }
 
@@ -272,18 +279,15 @@ class CachingSpec extends Specification {
     // ========== HTTP Endpoint Tests ==========
 
     def "basic cache works via HTTP"() {
-        given:
-        def client = createClient()
-        
         // Evict cache to start fresh
         client.toBlocking().exchange(HttpRequest.GET('/cacheTest/evictBasic'), String)
 
         when: "calling endpoint twice"
-        HttpResponse<String> response1 = client.toBlocking().exchange(
+        def response1 = client.toBlocking().exchange(
             HttpRequest.GET('/cacheTest/basicData'),
             String
         )
-        HttpResponse<String> response2 = client.toBlocking().exchange(
+        def response2 = client.toBlocking().exchange(
             HttpRequest.GET('/cacheTest/basicData'),
             String
         )
@@ -296,24 +300,18 @@ class CachingSpec extends Specification {
         def json2 = new JsonSlurper().parseText(response2.body())
         
         json1.data == json2.data
-
-        cleanup:
-        client.close()
     }
 
     def "parameter cache works via HTTP"() {
-        given:
-        def client = createClient()
-        
         // Evict cache
         client.toBlocking().exchange(HttpRequest.GET('/cacheTest/evictAllParam'), String)
 
         when: "calling with same ID twice"
-        HttpResponse<String> response1 = client.toBlocking().exchange(
+        def response1 = client.toBlocking().exchange(
             HttpRequest.GET('/cacheTest/dataById?id=42'),
             String
         )
-        HttpResponse<String> response2 = client.toBlocking().exchange(
+        def response2 = client.toBlocking().exchange(
             HttpRequest.GET('/cacheTest/dataById?id=42'),
             String
         )
@@ -323,24 +321,21 @@ class CachingSpec extends Specification {
         def json2 = new JsonSlurper().parseText(response2.body())
         
         json1.data == json2.data
-
-        cleanup:
-        client.close()
     }
 
     def "eviction works via HTTP"() {
-        given:
-        def client = createClient()
-        
         // Evict cache and populate it
         client.toBlocking().exchange(HttpRequest.GET('/cacheTest/evictBasic'), String)
-        def firstCall = client.toBlocking().exchange(HttpRequest.GET('/cacheTest/basicData'), String)
+        def firstCall = client.toBlocking().exchange(
+                HttpRequest.GET('/cacheTest/basicData'),
+                String
+        )
         def firstData = new JsonSlurper().parseText(firstCall.body()).data
 
         when: "evicting via HTTP then calling again after delay"
         client.toBlocking().exchange(HttpRequest.GET('/cacheTest/evictBasic'), String)
         Thread.sleep(10) // Ensure timestamp changes
-        HttpResponse<String> afterEvict = client.toBlocking().exchange(
+        def afterEvict = client.toBlocking().exchange(
             HttpRequest.GET('/cacheTest/basicData'),
             String
         )
@@ -348,14 +343,10 @@ class CachingSpec extends Specification {
         then: "new data generated after eviction"
         def afterEvictData = new JsonSlurper().parseText(afterEvict.body()).data
         firstData != afterEvictData
-
-        cleanup:
-        client.close()
     }
 
     def "different IDs return different cached values via HTTP"() {
         given:
-        def client = createClient()
         client.toBlocking().exchange(HttpRequest.GET('/cacheTest/evictAllParam'), String)
 
         when: "fetching different IDs"
@@ -370,15 +361,9 @@ class CachingSpec extends Specification {
         
         json1.data != json2.data
         json1.data == json3.data
-
-        cleanup:
-        client.close()
     }
 
     def "complex data endpoint works with caching"() {
-        given:
-        def client = createClient()
-
         when: "fetching complex data"
         def response1 = client.toBlocking().exchange(
             HttpRequest.GET('/cacheTest/complexData?category=electronics&page=3'),
@@ -396,15 +381,9 @@ class CachingSpec extends Specification {
         json1.data == json2.data
         json1.data.category == 'electronics'
         json1.data.page == 3
-
-        cleanup:
-        client.close()
     }
 
     def "CachePut works via HTTP with key closure"() {
-        given:
-        def client = createClient()
-        
         // Evict keyed cache and get initial value
         client.toBlocking().exchange(HttpRequest.GET('/cacheTest/evictAllKeyed'), String)
         def initial = new JsonSlurper().parseText(
@@ -412,16 +391,16 @@ class CachingSpec extends Specification {
         ).data
 
         when: "updating via HTTP"
-        client.toBlocking().exchange(HttpRequest.GET('/cacheTest/updateByKey?key=httpkey&value=HTTPUpdated'), String)
+        client.toBlocking().exchange(
+                HttpRequest.GET('/cacheTest/updateByKey?key=httpkey&value=HTTPUpdated'),
+                String
+        )
         def afterUpdate = new JsonSlurper().parseText(
             client.toBlocking().exchange(HttpRequest.GET('/cacheTest/byKey?key=httpkey'), String).body()
         ).data
 
         then: "cache contains updated value"
-        afterUpdate == "HTTPUpdated"
+        afterUpdate == 'HTTPUpdated'
         afterUpdate != initial
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/codecs/SecurityCodecsSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/codecs/SecurityCodecsSpec.groovy
index 80879971af..ad19ab280e 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/codecs/SecurityCodecsSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/codecs/SecurityCodecsSpec.groovy
@@ -16,15 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.codecs
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.client.HttpClient
+import spock.lang.Shared
 import spock.lang.Specification
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Comprehensive integration tests for Grails codec functionality.
  * 
@@ -39,19 +39,23 @@ import spock.lang.Specification
  * - Edge cases (null, empty, special characters)
  * - Hash consistency verification
  */
-@Integration(applicationClass = Application)
+@Integration
 class SecurityCodecsSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== HTML Encoding Tests (XSS Prevention) ==========
 
     def "test HTML encoding escapes dangerous tags"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeHtml?input=%3Cscript%3Ealert(%22XSS%22)%3C/script%3E'),
@@ -65,15 +69,9 @@ class SecurityCodecsSpec extends Specification {
         response.body().encoded.contains('&lt;/script&gt;')
         !response.body().encoded.contains('<script>')
         response.body().decodedBack == '<script>alert("XSS")</script>'
-
-        cleanup:
-        client.close()
     }
 
     def "test HTML encoding escapes quotes"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeHtml?input=%22quoted%22'),
@@ -84,15 +82,9 @@ class SecurityCodecsSpec extends Specification {
         response.status.code == 200
         response.body().encoded.contains('&quot;')
         response.body().decodedBack == '"quoted"'
-
-        cleanup:
-        client.close()
     }
 
     def "test HTML encoding escapes ampersands"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeHtml?input=foo%26bar'),
@@ -104,17 +96,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().input == 'foo&bar'
         response.body().encoded.contains('&amp;')
         response.body().decodedBack == 'foo&bar'
-
-        cleanup:
-        client.close()
     }
 
     // ========== URL Encoding Tests ==========
 
     def "test URL encoding escapes spaces and special chars"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeUrl?input=hello+world%26foo%3Dbar'),
@@ -128,17 +114,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().encoded.contains('%26')
         response.body().encoded.contains('%3D')
         response.body().decodedBack == 'hello world&foo=bar'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Base64 Encoding Tests ==========
 
     def "test Base64 encoding and decoding text"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeBase64?input=Hello%2C+World!'),
@@ -150,15 +130,9 @@ class SecurityCodecsSpec extends Specification {
         response.body().input == 'Hello, World!'
         response.body().encoded == 'SGVsbG8sIFdvcmxkIQ=='
         response.body().decodedBack == 'Hello, World!'
-
-        cleanup:
-        client.close()
     }
 
     def "test Base64 encoding with binary data"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeBase64Binary'),
@@ -170,17 +144,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().originalBytes == [72, 101, 108, 108, 111] // "Hello" in ASCII
         response.body().encoded == 'SGVsbG8='
         response.body().decodedBytes == [72, 101, 108, 108, 111]
-
-        cleanup:
-        client.close()
     }
 
     // ========== MD5 Hash Tests ==========
 
     def "test MD5 hashing produces consistent 32-char hex string"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeMd5?input=password123'),
@@ -192,15 +160,9 @@ class SecurityCodecsSpec extends Specification {
         response.body().input == 'password123'
         response.body().hashLength == 32
         response.body().md5Hash ==~ /^[a-f0-9]{32}$/
-
-        cleanup:
-        client.close()
     }
 
     def "test MD5 bytes produces 16 bytes"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeMd5Bytes?input=password123'),
@@ -211,17 +173,11 @@ class SecurityCodecsSpec extends Specification {
         response.status.code == 200
         response.body().bytesLength == 16
         response.body().md5Bytes.size() == 16
-
-        cleanup:
-        client.close()
     }
 
     // ========== SHA1 Hash Tests ==========
 
     def "test SHA1 hashing produces consistent 40-char hex string"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSha1?input=password123'),
@@ -232,15 +188,9 @@ class SecurityCodecsSpec extends Specification {
         response.status.code == 200
         response.body().hashLength == 40
         response.body().sha1Hash ==~ /^[a-f0-9]{40}$/
-
-        cleanup:
-        client.close()
     }
 
     def "test SHA1 bytes produces 20 bytes"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSha1Bytes?input=password123'),
@@ -250,17 +200,11 @@ class SecurityCodecsSpec extends Specification {
         then: "SHA1 bytes should be 20 bytes"
         response.status.code == 200
         response.body().bytesLength == 20
-
-        cleanup:
-        client.close()
     }
 
     // ========== SHA256 Hash Tests ==========
 
     def "test SHA256 hashing produces consistent 64-char hex string"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSha256?input=password123'),
@@ -271,15 +215,9 @@ class SecurityCodecsSpec extends Specification {
         response.status.code == 200
         response.body().hashLength == 64
         response.body().sha256Hash ==~ /^[a-f0-9]{64}$/
-
-        cleanup:
-        client.close()
     }
 
     def "test SHA256 bytes produces 32 bytes"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSha256Bytes?input=password123'),
@@ -289,17 +227,11 @@ class SecurityCodecsSpec extends Specification {
         then: "SHA256 bytes should be 32 bytes"
         response.status.code == 200
         response.body().bytesLength == 32
-
-        cleanup:
-        client.close()
     }
 
     // ========== Hex Encoding Tests ==========
 
     def "test Hex encoding and decoding"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeHex?input=Hello'),
@@ -311,17 +243,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().input == 'Hello'
         response.body().hexEncoded == '48656c6c6f' // "Hello" in hex
         response.body().decodedBack == 'Hello'
-
-        cleanup:
-        client.close()
     }
 
     // ========== JavaScript Encoding Tests ==========
 
     def "test JavaScript encoding escapes quotes and newlines"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/codecTest/encodeJavaScript"),
@@ -335,17 +261,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().input.contains('\n')
         // The encoded output should escape these characters
         response.body().encoded.contains("\\'") || response.body().encoded.contains("\\u0027")
-
-        cleanup:
-        client.close()
     }
 
     // ========== Raw Output Tests ==========
 
     def "test Raw encoding preserves content without escaping"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeRaw'),
@@ -356,17 +276,11 @@ class SecurityCodecsSpec extends Specification {
         response.status.code == 200
         response.body().input == '<b>Bold</b>'
         response.body().raw == '<b>Bold</b>'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Multiple Encodings Tests ==========
 
     def "test chaining multiple encodings"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/multipleEncodings'),
@@ -378,17 +292,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().input == '<script>alert(1)</script>'
         response.body().htmlEncoded.contains('&lt;')
         response.body().fullyDecoded == '<script>alert(1)</script>'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Special Characters Tests ==========
 
     def "test encoding with Unicode and special characters"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSpecialChars?input=%E6%97%A5%E6%9C%AC%E8%AA%9E+%26+%C3%A9moji+%F0%9F%91%8D+%3Ctag%3E'),
@@ -401,17 +309,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().htmlEncoded.contains('&lt;tag&gt;')
         response.body().urlEncoded != null
         response.body().base64Encoded != null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Null Handling Tests ==========
 
     def "test encoding null values returns null safely"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeNull'),
@@ -423,17 +325,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().nullBase64 == null
         response.body().nullMd5 == null
         response.body().nullHtml == null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Empty String Tests ==========
 
     def "test encoding empty strings"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeEmpty'),
@@ -450,17 +346,11 @@ class SecurityCodecsSpec extends Specification {
         response.body().md5Hash.length() == 32
         response.body().sha256Hash != null
         response.body().sha256Hash.length() == 64
-
-        cleanup:
-        client.close()
     }
 
     // ========== Hash Consistency Tests ==========
 
     def "test hash functions produce consistent results"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/hashConsistency?input=test-consistency'),
@@ -472,15 +362,9 @@ class SecurityCodecsSpec extends Specification {
         response.body().md5Consistent == true
         response.body().sha1Consistent == true
         response.body().sha256Consistent == true
-
-        cleanup:
-        client.close()
     }
 
     def "test different inputs produce different hashes"() {
-        given:
-        def client = createClient()
-
         when:
         def response1 = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/hashConsistency?input=input1'),
@@ -497,17 +381,11 @@ class SecurityCodecsSpec extends Specification {
         response1.body().md5Hash != response2.body().md5Hash
         response1.body().sha1Hash != response2.body().sha1Hash
         response1.body().sha256Hash != response2.body().sha256Hash
-
-        cleanup:
-        client.close()
     }
 
     // ========== Known Hash Values Tests ==========
 
     def "test MD5 produces known hash for 'hello'"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeMd5?input=hello'),
@@ -517,15 +395,9 @@ class SecurityCodecsSpec extends Specification {
         then: "MD5 of 'hello' should match known value"
         response.status.code == 200
         response.body().md5Hash == '5d41402abc4b2a76b9719d911017c592'
-
-        cleanup:
-        client.close()
     }
 
     def "test SHA1 produces known hash for 'hello'"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSha1?input=hello'),
@@ -535,15 +407,9 @@ class SecurityCodecsSpec extends Specification {
         then: "SHA1 of 'hello' should match known value"
         response.status.code == 200
         response.body().sha1Hash == 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
-
-        cleanup:
-        client.close()
     }
 
     def "test SHA256 produces known hash for 'hello'"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/codecTest/encodeSha256?input=hello'),
@@ -553,8 +419,5 @@ class SecurityCodecsSpec extends Specification {
         then: "SHA256 of 'hello' should match known value"
         response.status.code == 200
         response.body().sha256Hash == '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/commanddi/CommandObjectDISpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/commanddi/CommandObjectDISpec.groovy
index c8deb67716..0762550402 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/commanddi/CommandObjectDISpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/commanddi/CommandObjectDISpec.groovy
@@ -16,36 +16,40 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.commanddi
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.client.HttpClient
+import spock.lang.Shared
 import spock.lang.Specification
 import spock.lang.Unroll
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for Command Objects with Dependency Injection.
  * Tests the ability to inject Spring services into Grails command objects.
  */
-@Integration(applicationClass = Application)
+@Integration
 class CommandObjectDISpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Basic Service Injection Tests ==========
 
     def "service is properly injected into command object"() {
-        given: "a request to test service injection"
-        def client = createClient()
-
         when: "calling the test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testServiceInjection"),
+            HttpRequest.GET('/commandDI/testServiceInjection'),
             Map
         )
 
@@ -53,18 +57,12 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().serviceInjected == true
         response.body().serviceId == 'ValidationHelperService-v1'
-
-        cleanup:
-        client.close()
     }
 
     def "multiple services can be injected into single command object"() {
-        given: "a request to test multiple service injection"
-        def client = createClient()
-
         when: "calling the endpoint with order command"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testMultipleServices"),
+            HttpRequest.GET('/commandDI/testMultipleServices'),
             Map
         )
 
@@ -74,18 +72,12 @@ class CommandObjectDISpec extends Specification {
         response.body().notificationServiceInjected == true
         response.body().pricingServiceId == 'PricingService-v1'
         response.body().notificationServiceId == 'NotificationService-v1'
-
-        cleanup:
-        client.close()
     }
 
     def "@Autowired annotation works for service injection"() {
-        given: "a request to test @Autowired injection"
-        def client = createClient()
-
         when: "calling the endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testAutowiredAnnotation"),
+            HttpRequest.GET('/commandDI/testAutowiredAnnotation'),
             Map
         )
 
@@ -93,20 +85,14 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().serviceInjected == true
         response.body().serviceId == 'ValidationHelperService-v1'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Validation with Injected Service Tests ==========
 
     def "custom validation using injected service - valid username"() {
-        given: "a valid user registration request"
-        def client = createClient()
-
         when: "registering with valid data"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/registerUser?username=johndoe&email=john@example.com&age=25"),
+            HttpRequest.GET('/commandDI/registerUser?username=johndoe&email=john@example.com&age=25'),
             Map
         )
 
@@ -116,18 +102,12 @@ class CommandObjectDISpec extends Specification {
         response.body().errors.isEmpty()
         response.body().username == 'johndoe'
         response.body().usernameAvailable == true
-
-        cleanup:
-        client.close()
     }
 
     def "custom validation using injected service - reserved username rejected"() {
-        given: "a registration request with reserved username"
-        def client = createClient()
-
         when: "registering with reserved username 'admin'"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/registerUser?username=admin&email=admin@example.com"),
+            HttpRequest.GET('/commandDI/registerUser?username=admin&email=admin@example.com'),
             Map
         )
 
@@ -136,16 +116,10 @@ class CommandObjectDISpec extends Specification {
         response.body().valid == false
         response.body().errors.any { it.field == 'username' }
         response.body().usernameAvailable == false
-
-        cleanup:
-        client.close()
     }
 
     @Unroll
     def "email domain validation - #email is #expectedResult"() {
-        given: "a registration request with specific email"
-        def client = createClient()
-
         when: "registering with specific email"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/commandDI/registerUser?username=testuser&email=${URLEncoder.encode(email, 'UTF-8')}"),
@@ -156,9 +130,6 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().valid == expectedValid
 
-        cleanup:
-        client.close()
-
         where:
         email                    | expectedValid | expectedResult
         'user@example.com'       | true          | 'valid'
@@ -170,9 +141,6 @@ class CommandObjectDISpec extends Specification {
 
     @Unroll
     def "age validation - age #age is #expectedResult"() {
-        given: "a registration request with specific age"
-        def client = createClient()
-
         when: "registering with specific age"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/commandDI/registerUser?username=testuser&email=user@example.com&age=${age}"),
@@ -187,9 +155,6 @@ class CommandObjectDISpec extends Specification {
             response.body().errors.any { it.field == 'age' }
         }
 
-        cleanup:
-        client.close()
-
         where:
         age  | expectedValid | expectedResult
         18   | true          | 'valid (minimum)'
@@ -200,48 +165,33 @@ class CommandObjectDISpec extends Specification {
     }
 
     def "phone number validation using service"() {
-        given: "a registration request with phone number"
-        def client = createClient()
-
         when: "registering with valid phone"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/registerUser?username=testuser&email=user@example.com&phone=555-123-4567"),
+            HttpRequest.GET('/commandDI/registerUser?username=testuser&email=user@example.com&phone=555-123-4567'),
             Map
         )
 
         then: "validation passes for valid phone"
         response.status.code == 200
         response.body().errors.findAll { it.field == 'phone' }.isEmpty()
-
-        cleanup:
-        client.close()
     }
 
     def "phone number validation fails for invalid phone"() {
-        given: "a registration request with invalid phone"
-        def client = createClient()
-
         when: "registering with too short phone"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/registerUser?username=testuser&email=user@example.com&phone=123"),
+            HttpRequest.GET('/commandDI/registerUser?username=testuser&email=user@example.com&phone=123'),
             Map
         )
 
         then: "validation fails for invalid phone"
         response.status.code == 200
         response.body().errors.any { it.field == 'phone' }
-
-        cleanup:
-        client.close()
     }
 
     // ========== Calculated Properties Tests ==========
 
     @Unroll
     def "discount calculation - quantity #quantity gives #expectedDiscount discount"() {
-        given: "an order with specific quantity"
-        def client = createClient()
-
         when: "calculating order"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/commandDI/calculateOrder?productName=Widget&quantity=${quantity}&unitPrice=10.00"),
@@ -252,9 +202,6 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().discount == expectedDiscount
 
-        cleanup:
-        client.close()
-
         where:
         quantity | expectedDiscount
         1        | 0.0
@@ -268,30 +215,21 @@ class CommandObjectDISpec extends Specification {
     }
 
     def "total price calculation with discount"() {
-        given: "an order for 100 items at 10 dollars each"
-        def client = createClient()
-
         when: "calculating order"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/calculateOrder?productName=Widget&quantity=100&unitPrice=10.00"),
+            HttpRequest.GET('/commandDI/calculateOrder?productName=Widget&quantity=100&unitPrice=10.00'),
             Map
         )
 
         then: "total price includes 25% discount (100*10=1000, minus 25% = 750)"
         response.status.code == 200
         response.body().totalPrice == 750.0
-
-        cleanup:
-        client.close()
     }
 
     def "price with tax calculation"() {
-        given: "an order for 10 items at 100 dollars each"
-        def client = createClient()
-
         when: "calculating order"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/calculateOrder?productName=Premium+Widget&quantity=10&unitPrice=100.00"),
+            HttpRequest.GET('/commandDI/calculateOrder?productName=Premium+Widget&quantity=10&unitPrice=100.00'),
             Map
         )
 
@@ -299,20 +237,14 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().totalPrice == 900.0
         response.body().priceWithTax == 972.0
-
-        cleanup:
-        client.close()
     }
 
     // ========== Order Validation Tests ==========
 
     def "order validation with valid data"() {
-        given: "a valid order"
-        def client = createClient()
-
         when: "validating order"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/validateOrder?productName=Widget&quantity=5&unitPrice=25.00"),
+            HttpRequest.GET('/commandDI/validateOrder?productName=Widget&quantity=5&unitPrice=25.00'),
             Map
         )
 
@@ -320,18 +252,12 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().valid == true
         response.body().errors.isEmpty()
-
-        cleanup:
-        client.close()
     }
 
     def "order validation fails for price out of range"() {
-        given: "an order with price too high"
-        def client = createClient()
-
         when: "validating order with excessive price"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/validateOrder?productName=Widget&quantity=5&unitPrice=99999.00"),
+            HttpRequest.GET('/commandDI/validateOrder?productName=Widget&quantity=5&unitPrice=99999.00'),
             Map
         )
 
@@ -339,20 +265,14 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().valid == false
         response.body().errors.any { it.field == 'unitPrice' }
-
-        cleanup:
-        client.close()
     }
 
     // ========== Service Method Invocation Tests ==========
 
     def "command object can invoke service method to send notification"() {
-        given: "a notification request"
-        def client = createClient()
-
         when: "sending order notification"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/sendOrderNotification?customerEmail=customer@example.com&orderId=ORD-12345&message=Thank+you+for+your+order!"),
+            HttpRequest.GET('/commandDI/sendOrderNotification?customerEmail=customer@example.com&orderId=ORD-12345&message=Thank+you+for+your+order!'),
             Map
         )
 
@@ -361,20 +281,14 @@ class CommandObjectDISpec extends Specification {
         response.body().notificationSent == true
         response.body().lastNotification.recipient == 'customer@example.com'
         response.body().lastNotification.message == 'Thank you for your order!'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Prototype Scope Tests ==========
 
     def "command object is prototype scoped - fresh instance per request"() {
-        given: "two separate requests"
-        def client = createClient()
-
         when: "making first request"
         def response1 = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testPrototypeScope"),
+            HttpRequest.GET('/commandDI/testPrototypeScope'),
             Map
         )
 
@@ -384,7 +298,7 @@ class CommandObjectDISpec extends Specification {
 
         when: "making second request"
         def response2 = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testPrototypeScope"),
+            HttpRequest.GET('/commandDI/testPrototypeScope'),
             Map
         )
 
@@ -392,20 +306,14 @@ class CommandObjectDISpec extends Specification {
         response2.status.code == 200
         response2.body().counter == 2
         response2.body().expectedValue == 2
-
-        cleanup:
-        client.close()
     }
 
     // ========== Service Persistence Tests ==========
 
     def "service remains injected after validation"() {
-        given: "a request to test service persistence"
-        def client = createClient()
-
         when: "testing service after validation"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testServiceAfterValidation?username=admin&email=test@example.com"),
+            HttpRequest.GET('/commandDI/testServiceAfterValidation?username=admin&email=test@example.com'),
             Map
         )
 
@@ -413,20 +321,14 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().serviceAfterFirst == true
         response.body().serviceAfterSecond == true
-
-        cleanup:
-        client.close()
     }
 
     // ========== Optional Service Tests ==========
 
     def "missing optional service is handled gracefully"() {
-        given: "a command with optional service"
-        def client = createClient()
-
         when: "testing optional service"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/testOptionalService?data=test"),
+            HttpRequest.GET('/commandDI/testOptionalService?data=test'),
             Map
         )
 
@@ -434,20 +336,14 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().requiredServicePresent == true
         response.body().optionalServicePresent == false
-
-        cleanup:
-        client.close()
     }
 
     // ========== State Dependent Validation Tests ==========
 
     def "validation can depend on service state"() {
-        given: "a request with price"
-        def client = createClient()
-
         when: "validating with positive price"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/validateWithServiceState?price=100.00"),
+            HttpRequest.GET('/commandDI/validateWithServiceState?price=100.00'),
             Map
         )
 
@@ -455,36 +351,24 @@ class CommandObjectDISpec extends Specification {
         response.status.code == 200
         response.body().valid == true
         response.body().currentTaxRate == 0.08
-
-        cleanup:
-        client.close()
     }
 
     // ========== Edge Cases ==========
 
     def "command object handles valid user request"() {
-        given: "a basic valid request"
-        def client = createClient()
-
         when: "validating user"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/commandDI/registerUser?username=validuser&email=user@example.com"),
+            HttpRequest.GET('/commandDI/registerUser?username=validuser&email=user@example.com'),
             Map
         )
 
         then: "request succeeds"
         response.status.code == 200
         response.body().username == 'validuser'
-
-        cleanup:
-        client.close()
     }
 
     @Unroll
     def "reserved username '#username' is rejected"() {
-        given: "a registration request with reserved username"
-        def client = createClient()
-
         when: "registering with reserved username"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/commandDI/registerUser?username=${username}&email=test@example.com"),
@@ -496,9 +380,6 @@ class CommandObjectDISpec extends Specification {
         response.body().valid == false
         response.body().usernameAvailable == false
 
-        cleanup:
-        client.close()
-
         where:
         username << ['admin', 'root', 'system', 'administrator', 'ADMIN', 'Root']
     }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/constraints/ConstraintValidationSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/constraints/ConstraintValidationSpec.groovy
index edc0675ac8..25f8487515 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/constraints/ConstraintValidationSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/constraints/ConstraintValidationSpec.groovy
@@ -16,21 +16,20 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.constraints
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
 import spock.lang.Specification
 import spock.lang.Unroll
 
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for GORM constraint validation.
  * Tests built-in constraints, custom validators, and cross-field validation.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class ConstraintValidationSpec extends Specification {
 
     // ========== Product Constraints Tests ==========
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/contentneg/ContentNegotiationSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/contentneg/ContentNegotiationSpec.groovy
index 018eab6bdb..307561404e 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/contentneg/ContentNegotiationSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/contentneg/ContentNegotiationSpec.groovy
@@ -16,21 +16,21 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.contentneg
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import groovy.json.JsonSlurper
+
 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 io.micronaut.http.client.exceptions.HttpClientResponseException
 import spock.lang.Narrative
+import spock.lang.Shared
 import spock.lang.Specification
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for Grails content negotiation features.
  * 
@@ -38,7 +38,7 @@ import spock.lang.Specification
  * format selection, respond method, withFormat, and various
  * content type handling scenarios.
  */
-@Integration(applicationClass = Application)
+@Integration
 @Narrative('''
 Grails provides content negotiation that allows the same controller action
 to return different response formats (JSON, XML, HTML) based on the client's
@@ -46,18 +46,22 @@ Accept header or URL extension.
 ''')
 class ContentNegotiationSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Accept Header-Based Negotiation ==========
 
     def "JSON response via Accept header application/json"() {
-        given:
-        def client = createClient()
-
         when: "requesting with Accept: application/json"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/index')
                 .accept(MediaType.APPLICATION_JSON),
             String
@@ -71,17 +75,11 @@ class ContentNegotiationSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.message == 'Hello World'
         json.items.size() == 3
-
-        cleanup:
-        client.close()
     }
 
     def "XML response via Accept header application/xml"() {
-        given:
-        def client = createClient()
-
         when: "requesting with Accept: application/xml"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/index')
                 .accept(MediaType.APPLICATION_XML),
             String
@@ -93,17 +91,11 @@ class ContentNegotiationSpec extends Specification {
         
         and: "content contains expected XML elements (Grails XML converter uses entry key format for maps)"
         response.body().contains('<entry key="message">Hello World</entry>')
-
-        cleanup:
-        client.close()
     }
 
     def "HTML response via Accept header text/html"() {
-        given:
-        def client = createClient()
-
         when: "requesting with Accept: text/html"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/index')
                 .accept(MediaType.TEXT_HTML),
             String
@@ -116,19 +108,13 @@ class ContentNegotiationSpec extends Specification {
         and: "content is HTML page"
         response.body().contains('<h1>Content Negotiation</h1>')
         response.body().contains('Hello World')
-
-        cleanup:
-        client.close()
     }
 
     // ========== URL Extension-Based Negotiation ==========
 
     def "JSON response via .json extension"() {
-        given:
-        def client = createClient()
-
         when: "requesting URL with .json extension"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/index.json'),
             String
         )
@@ -139,17 +125,11 @@ class ContentNegotiationSpec extends Specification {
         and: "content is valid JSON with expected data"
         def json = new JsonSlurper().parseText(response.body())
         json.message == 'Hello World'
-
-        cleanup:
-        client.close()
     }
 
     def "XML response via .xml extension"() {
-        given:
-        def client = createClient()
-
         when: "requesting URL with .xml extension"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/index.xml'),
             String
         )
@@ -159,19 +139,13 @@ class ContentNegotiationSpec extends Specification {
         
         and: "content is XML (Grails converter uses map/entry format)"
         response.body().contains('<entry key="message">')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Respond Method Tests ==========
 
     def "respond method returns JSON for Accept application/json"() {
-        given:
-        def client = createClient()
-
         when: "calling respond action with Accept: application/json"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/respond')
                 .accept(MediaType.APPLICATION_JSON),
             String
@@ -185,17 +159,11 @@ class ContentNegotiationSpec extends Specification {
         json.status == 'success'
         json.data.id == 1
         json.data.name == 'Test Item'
-
-        cleanup:
-        client.close()
     }
 
     def "respond method returns XML for Accept application/xml"() {
-        given:
-        def client = createClient()
-
         when: "calling respond action with Accept: application/xml"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/respond')
                 .accept(MediaType.APPLICATION_XML),
             String
@@ -204,19 +172,13 @@ class ContentNegotiationSpec extends Specification {
         then: "response is XML"
         response.status == HttpStatus.OK
         response.contentType.get().toString().contains('xml')
-
-        cleanup:
-        client.close()
     }
 
     // ========== List/Collection Content Negotiation ==========
 
     def "list action returns JSON array"() {
-        given:
-        def client = createClient()
-
         when: "requesting list with Accept: application/json"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/list')
                 .accept(MediaType.APPLICATION_JSON),
             String
@@ -231,17 +193,11 @@ class ContentNegotiationSpec extends Specification {
         json.size() == 3
         json[0].id == 1
         json[0].name == 'Item 1'
-
-        cleanup:
-        client.close()
     }
 
     def "list action returns XML for XML accept"() {
-        given:
-        def client = createClient()
-
         when: "requesting list with Accept: application/xml"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/list')
                 .accept(MediaType.APPLICATION_XML),
             String
@@ -250,19 +206,13 @@ class ContentNegotiationSpec extends Specification {
         then: "response is XML"
         response.status == HttpStatus.OK
         response.contentType.get().toString().contains('xml')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Explicit Content Type ==========
 
     def "explicit content type overrides negotiation"() {
-        given:
-        def client = createClient()
-
         when: "calling action with explicit content type"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/explicitContentType'),
             String
         )
@@ -274,17 +224,11 @@ class ContentNegotiationSpec extends Specification {
         and: "content is as specified"
         def json = new JsonSlurper().parseText(response.body())
         json.explicit == true
-
-        cleanup:
-        client.close()
     }
 
     // ========== Error Response Formatting ==========
 
     def "error response in JSON format"() {
-        given:
-        def client = createClient()
-
         when: "requesting error action with Accept: application/json"
         client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/error')
@@ -293,7 +237,7 @@ class ContentNegotiationSpec extends Specification {
         )
 
         then: "error response is returned"
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.BAD_REQUEST
         
         and: "error body is JSON"
@@ -301,15 +245,9 @@ class ContentNegotiationSpec extends Specification {
         json.error == true
         json.message == 'Something went wrong'
         json.code == 'ERR_001'
-
-        cleanup:
-        client.close()
     }
 
     def "error response in XML format"() {
-        given:
-        def client = createClient()
-
         when: "requesting error action with Accept: application/xml"
         client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/error')
@@ -318,24 +256,18 @@ class ContentNegotiationSpec extends Specification {
         )
 
         then: "error response is returned"
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.BAD_REQUEST
         
         and: "error body contains XML elements (Grails converter uses entry key format)"
         e.response.body().toString().contains('<entry key="error">true</entry>')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Format Parameter Override ==========
 
     def "format parameter can specify JSON"() {
-        given:
-        def client = createClient()
-
         when: "requesting with format=json parameter"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/formatParam?format=json'),
             String
         )
@@ -347,17 +279,11 @@ class ContentNegotiationSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.format == 'json'
         json.value == 42
-
-        cleanup:
-        client.close()
     }
 
     def "format parameter can specify XML"() {
-        given:
-        def client = createClient()
-
         when: "requesting with format=xml parameter"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/formatParam?format=xml'),
             String
         )
@@ -365,19 +291,13 @@ class ContentNegotiationSpec extends Specification {
         then: "response is XML"
         response.status == HttpStatus.OK
         response.body().contains('<entry key="format">xml</entry>')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Status Code Tests ==========
 
     def "status by format returns correct status for JSON"() {
-        given:
-        def client = createClient()
-
         when: "requesting statusByFormat with Accept: application/json"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/statusByFormat')
                 .accept(MediaType.APPLICATION_JSON),
             String
@@ -389,19 +309,13 @@ class ContentNegotiationSpec extends Specification {
         and: "body is JSON"
         def json = new JsonSlurper().parseText(response.body())
         json.status == 'ok'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Accept Header Quality Values ==========
 
     def "multiAccept action handles Accept header"() {
-        given:
-        def client = createClient()
-
         when: "requesting with complex Accept header"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/multiAccept')
                 .accept(MediaType.APPLICATION_JSON),
             String
@@ -413,19 +327,13 @@ class ContentNegotiationSpec extends Specification {
         and: "response contains accept header info"
         def json = new JsonSlurper().parseText(response.body())
         json.acceptHeader != null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Wildcard/Default Format ==========
 
     def "formatParam falls back to default for unknown format"() {
-        given:
-        def client = createClient()
-
         when: "requesting with unknown format"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/formatParam?format=unknown'),
             String
         )
@@ -437,19 +345,13 @@ class ContentNegotiationSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.format == 'unknown'
         json.value == 42
-
-        cleanup:
-        client.close()
     }
 
     // ========== Content-Type Header Variations ==========
 
     def "JSON with charset in Accept header"() {
-        given:
-        def client = createClient()
-
         when: "requesting with Accept including charset"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/respond')
                 .header('Accept', 'application/json; charset=utf-8'),
             String
@@ -458,19 +360,13 @@ class ContentNegotiationSpec extends Specification {
         then: "response is JSON"
         response.status == HttpStatus.OK
         response.contentType.get().toString().contains('json')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Multiple Format Extensions ==========
 
     def "respond action with .json extension"() {
-        given:
-        def client = createClient()
-
         when: "requesting respond with .json extension"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/respond.json'),
             String
         )
@@ -481,17 +377,11 @@ class ContentNegotiationSpec extends Specification {
         and: "content is valid"
         def json = new JsonSlurper().parseText(response.body())
         json.status == 'success'
-
-        cleanup:
-        client.close()
     }
 
     def "list action with .json extension"() {
-        given:
-        def client = createClient()
-
         when: "requesting list with .json extension"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/list.json'),
             String
         )
@@ -503,19 +393,13 @@ class ContentNegotiationSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json instanceof List
         json.size() == 3
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom JSON Rendering ==========
 
     def "custom JSON rendering produces valid output"() {
-        given:
-        def client = createClient()
-
         when: "requesting custom JSON action"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/contentNegotiation/customJson'),
             String
         )
@@ -523,8 +407,5 @@ class ContentNegotiationSpec extends Specification {
         then: "response is JSON"
         response.status == HttpStatus.OK
         response.contentType.get().toString().contains('application/json')
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/cors/CorsAdvancedSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/cors/CorsAdvancedSpec.groovy
index bf86e37560..951db909f2 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/cors/CorsAdvancedSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/cors/CorsAdvancedSpec.groovy
@@ -18,17 +18,17 @@
  */
 package functionaltests.cors
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
 import groovy.json.JsonSlurper
+
 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.Specification
 import spock.lang.Shared
+import spock.lang.Specification
+
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for CORS (Cross-Origin Resource Sharing) functionality.
@@ -36,26 +36,26 @@ import spock.lang.Shared
  * 
  * Note: CORS is enabled for /api/** in application.yml
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class CorsAdvancedSpec extends Specification {
 
     @Shared
     HttpClient client
 
     def setup() {
-        client = HttpClient.create(new URL("http://localhost:${serverPort}"))
+        client = client ?: HttpClient.create(new URL("http://localhost:${serverPort}"))
     }
 
-    def cleanup() {
-        client?.close()
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Basic CORS Header Tests ==========
 
     def "GET request to CORS-enabled endpoint includes CORS headers"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors')
                 .header('Origin', 'http://example.com'),
             String
@@ -69,7 +69,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "OPTIONS preflight request returns appropriate headers"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.OPTIONS('/api/cors/data')
                 .header('Origin', 'http://example.com')
                 .header('Access-Control-Request-Method', 'GET'),
@@ -84,7 +84,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "preflight request for POST method succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.OPTIONS('/api/cors/items')
                 .header('Origin', 'http://example.com')
                 .header('Access-Control-Request-Method', 'POST')
@@ -100,7 +100,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "preflight request for PUT method succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.OPTIONS('/api/cors/items/1')
                 .header('Origin', 'http://example.com')
                 .header('Access-Control-Request-Method', 'PUT')
@@ -114,7 +114,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "preflight request for DELETE method succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.OPTIONS('/api/cors/items/1')
                 .header('Origin', 'http://example.com')
                 .header('Access-Control-Request-Method', 'DELETE'),
@@ -129,7 +129,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "GET request to CORS endpoint returns data"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors/data')
                 .header('Origin', 'http://example.com'),
             String
@@ -144,7 +144,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "POST request with CORS headers succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/api/cors/items', '{"name":"New Item"}')
                 .header('Origin', 'http://example.com')
                 .contentType(MediaType.APPLICATION_JSON),
@@ -160,7 +160,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "PUT request with CORS headers succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.PUT('/api/cors/items/42', '{"name":"Updated Item"}')
                 .header('Origin', 'http://example.com')
                 .contentType(MediaType.APPLICATION_JSON),
@@ -177,7 +177,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "DELETE request with CORS headers succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.DELETE('/api/cors/items/99')
                 .header('Origin', 'http://example.com'),
             String
@@ -195,7 +195,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "response with custom headers includes CORS headers"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors/custom-headers')
                 .header('Origin', 'http://example.com'),
             String
@@ -210,7 +210,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "echo origin endpoint returns received origin"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors/echo-origin')
                 .header('Origin', 'http://my-app.example.com'),
             String
@@ -226,7 +226,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "authenticated endpoint receives authorization header"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors/authenticated')
                 .header('Origin', 'http://example.com')
                 .header('Authorization', 'Bearer test-token-123'),
@@ -242,7 +242,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "authenticated endpoint without credentials returns unauthenticated"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors/authenticated')
                 .header('Origin', 'http://example.com'),
             String
@@ -259,7 +259,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "request from localhost origin succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors')
                 .header('Origin', 'http://localhost:3000'),
             String
@@ -273,7 +273,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "request from HTTPS origin succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors')
                 .header('Origin', 'https://secure.example.com'),
             String
@@ -287,7 +287,7 @@ class CorsAdvancedSpec extends Specification {
 
     def "request with port in origin succeeds"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/cors')
                 .header('Origin', 'http://example.com:8080'),
             String
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/errorhandling/ErrorHandlingSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/errorhandling/ErrorHandlingSpec.groovy
index 9c28026cbc..79ff98bea7 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/errorhandling/ErrorHandlingSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/errorhandling/ErrorHandlingSpec.groovy
@@ -18,265 +18,119 @@
  */
 package functionaltests.errorhandling
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
 import groovy.json.JsonSlurper
+
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.HttpResponse
 import io.micronaut.http.HttpStatus
 import io.micronaut.http.client.HttpClient
 import io.micronaut.http.client.exceptions.HttpClientResponseException
-import spock.lang.Specification
 import spock.lang.Shared
+import spock.lang.Specification
 import spock.lang.Unroll
 
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for error handling patterns in Grails controllers.
  * Tests various HTTP status codes, JSON error responses, exception handling,
  * and error response headers.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class ErrorHandlingSpec extends Specification {
 
     @Shared
     HttpClient client
 
     def setup() {
-        client = HttpClient.create(new URL("http://localhost:${serverPort}"))
+        client = client ?: HttpClient.create(new URL("http://localhost:${serverPort}"))
     }
 
-    def cleanup() {
-        client?.close()
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== HTTP Status Code Tests ==========
 
-    def "render 404 Not Found status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderNotFound'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.NOT_FOUND
-    }
-
-    def "render 400 Bad Request status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderBadRequest'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.BAD_REQUEST
-    }
-
-    def "render 401 Unauthorized status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderUnauthorized'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.UNAUTHORIZED
-    }
-
-    def "render 403 Forbidden status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderForbidden'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.FORBIDDEN
-    }
-
-    def "render 405 Method Not Allowed status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderMethodNotAllowed'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.METHOD_NOT_ALLOWED
-    }
-
-    def "render 409 Conflict status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderConflict'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.CONFLICT
-    }
-
-    def "render 410 Gone status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderGone'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.GONE
-    }
-
-    def "render 422 Unprocessable Entity status"() {
+    @Unroll
+    def "render #statusMsg status"(String action, HttpStatus status, String statusMsg) {
         when:
         client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderUnprocessableEntity'),
+            HttpRequest.GET("/errorHandlingTest/$action"),
             String
         )
 
         then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.UNPROCESSABLE_ENTITY
-    }
+        def e = thrown(HttpClientResponseException)
+        e.status == status
 
-    def "render 429 Too Many Requests status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderTooManyRequests'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.TOO_MANY_REQUESTS
-    }
-
-    def "render 500 Internal Server Error status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderInternalServerError'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.INTERNAL_SERVER_ERROR
-    }
-
-    def "render 503 Service Unavailable status"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/renderServiceUnavailable'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.SERVICE_UNAVAILABLE
+        where:
+        action                      | status                           | statusMsg
+        'renderNotFound'            | HttpStatus.NOT_FOUND             | '404 Not Found'
+        'renderBadRequest'          | HttpStatus.BAD_REQUEST           | '400 Bad Request'
+        'renderUnauthorized'        | HttpStatus.UNAUTHORIZED          | '401 Unauthorized'
+        'renderForbidden'           | HttpStatus.FORBIDDEN             | '403 Forbidden'
+        'renderMethodNotAllowed'    | HttpStatus.METHOD_NOT_ALLOWED    | '405 Method Not Allowed'
+        'renderConflict'            | HttpStatus.CONFLICT              | '409 Conflict'
+        'renderGone'                | HttpStatus.GONE                  | '410 Gone'
+        'renderUnprocessableEntity' | HttpStatus.UNPROCESSABLE_ENTITY  | '422 Unprocessable Entity'
+        'renderTooManyRequests'     | HttpStatus.TOO_MANY_REQUESTS     | '429 Too Many Requests'
+        'renderInternalServerError' | HttpStatus.INTERNAL_SERVER_ERROR | '500 Internal Server Error'
+        'renderServiceUnavailable'  | HttpStatus.SERVICE_UNAVAILABLE   | '503 Service Unavailable'
     }
 
     // ========== JSON Error Response Tests ==========
 
-    def "JSON 404 error response contains proper structure"() {
+    @Unroll
+    def "JSON #statusCode.code error response #assertion"(String action, HttpStatus statusCode, String assertion) {
         when:
         client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/jsonNotFound').accept('application/json'),
+            HttpRequest.GET("/errorHandlingTest/$action")
+                    .accept('application/json'),
             String
         )
 
         then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.NOT_FOUND
-    }
-
-    def "JSON 400 error response with validation details"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/jsonBadRequest').accept('application/json'),
-            String
-        )
+        def e = thrown(HttpClientResponseException)
+        e.status == statusCode
 
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.BAD_REQUEST
-    }
-
-    def "JSON 422 validation error with multiple field errors"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/jsonValidationError').accept('application/json'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.UNPROCESSABLE_ENTITY
-    }
-
-    def "JSON 500 error response includes request ID"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/jsonServerError').accept('application/json'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.INTERNAL_SERVER_ERROR
+        where:
+        action                | statusCode                       | assertion
+        'jsonNotFound'        | HttpStatus.NOT_FOUND             | 'contains proper structure'
+        'jsonBadRequest'      | HttpStatus.BAD_REQUEST           | 'with validation details'
+        'jsonValidationError' | HttpStatus.UNPROCESSABLE_ENTITY  | 'with multiple field errors'
+        'jsonServerError'     | HttpStatus.INTERNAL_SERVER_ERROR | 'includes request ID'
     }
 
     // ========== Conditional Error Handling Tests ==========
 
-    def "conditional error returns 404 when condition is notfound"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/conditionalError?condition=notfound').accept('application/json'),
-            String
-        )
-
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.NOT_FOUND
-    }
-
-    def "conditional error returns 400 when condition is badrequest"() {
+    @Unroll
+    def "conditional error returns #status.code when condition is #condition"(String condition, HttpStatus status) {
         when:
         client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/conditionalError?condition=badrequest').accept('application/json'),
+            HttpRequest.GET("/errorHandlingTest/conditionalError?condition=$condition")
+                    .accept('application/json'),
             String
         )
 
         then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.BAD_REQUEST
-    }
-
-    def "conditional error returns 403 when condition is forbidden"() {
-        when:
-        client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/conditionalError?condition=forbidden').accept('application/json'),
-            String
-        )
+        def e = thrown(HttpClientResponseException)
+        e.status == status
 
-        then:
-        HttpClientResponseException e = thrown()
-        e.status == HttpStatus.FORBIDDEN
+        where:
+        condition     | status
+        'notfound'    | HttpStatus.NOT_FOUND
+        'badrequest'  | HttpStatus.BAD_REQUEST
+        'forbidden'   | HttpStatus.FORBIDDEN
     }
 
     def "conditional error returns success for unknown condition"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
-            HttpRequest.GET('/errorHandlingTest/conditionalError?condition=normal').accept('application/json'),
+        def response = client.toBlocking().exchange(
+            HttpRequest.GET('/errorHandlingTest/conditionalError?condition=normal')
+                    .accept('application/json'),
             String
         )
 
@@ -299,7 +153,7 @@ class ErrorHandlingSpec extends Specification {
         )
 
         then:
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.TOO_MANY_REQUESTS
 
         and:
@@ -318,7 +172,7 @@ class ErrorHandlingSpec extends Specification {
         )
 
         then:
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.NOT_FOUND
 
         and: "suggestion header is present"
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/events/DomainEventsSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/events/DomainEventsSpec.groovy
index d553dbf8e7..8bae3cfb27 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/events/DomainEventsSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/events/DomainEventsSpec.groovy
@@ -19,11 +19,11 @@
 
 package functionaltests.events
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
-import spock.lang.Specification
 import spock.lang.Narrative
+import spock.lang.Specification
+
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for GORM domain lifecycle events.
@@ -32,8 +32,8 @@ import spock.lang.Narrative
  * beforeDelete, afterDelete, beforeValidate, afterLoad events,
  * auto-timestamping, dirty checking, and event veto capabilities.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 @Narrative('''
 GORM provides lifecycle event hooks that are triggered during domain object
 persistence operations. These events allow for automatic auditing, validation,
@@ -91,7 +91,7 @@ class DomainEventsSpec extends Specification {
         def insertIndex = entity.eventLog.indexOf('beforeInsert')
         def afterIndex = entity.eventLog.indexOf('afterInsert')
         insertIndex >= 0
-        afterIndex >= 0
+        afterIndex > 0
         insertIndex < afterIndex
     }
 
@@ -136,8 +136,8 @@ class DomainEventsSpec extends Specification {
         then: "modified audit fields are updated"
         entity.modifiedAt != null
         entity.modifiedBy == 'system'
-        // modifiedAt should be different from original (which was null)
-        entity.modifiedAt != originalModifiedAt
+        // modifiedAt should be larger than original
+        entity.modifiedAt > originalModifiedAt
     }
 
     def "update events do not fire when entity is unchanged"() {
@@ -191,7 +191,7 @@ class DomainEventsSpec extends Specification {
         def beforeIndex = entity.eventLog.indexOf('beforeDelete')
         def afterIndex = entity.eventLog.indexOf('afterDelete')
         beforeIndex >= 0
-        afterIndex >= 0
+        afterIndex > 0
         beforeIndex < afterIndex
     }
 
@@ -230,6 +230,7 @@ class DomainEventsSpec extends Specification {
 
         then: "beforeValidate was triggered"
         entity.eventLog.contains('beforeValidate')
+
         and: "name was trimmed"
         entity.name == 'Trim On Save'
     }
@@ -288,7 +289,7 @@ class DomainEventsSpec extends Specification {
         entity.save(flush: true)
 
         then: "lastUpdated is updated"
-        entity.lastUpdated >= originalLastUpdated
+        entity.lastUpdated > originalLastUpdated
     }
 
     def "dateCreated remains unchanged on update"() {
@@ -296,7 +297,8 @@ class DomainEventsSpec extends Specification {
         def entity = new AuditedEntity(name: 'DateCreated Test').save(flush: true)
         def originalDateCreated = entity.dateCreated
 
-        when: "the entity is updated"
+        when: "the entity is updated after a brief pause"
+        sleep(10)
         entity.description = 'Modified'
         entity.save(flush: true)
 
@@ -550,10 +552,8 @@ class DomainEventsSpec extends Specification {
         def afterInsertIndex = entity.eventLog.indexOf('afterInsert')
         
         validateIndex >= 0
-        insertIndex >= 0
-        afterInsertIndex >= 0
-        // beforeValidate should come before beforeInsert
-        validateIndex < insertIndex || insertIndex < afterInsertIndex
+        insertIndex > validateIndex
+        afterInsertIndex > insertIndex
     }
 
     def "multiple entities have independent event logs"() {
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/fileupload/FileUploadSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/fileupload/FileUploadSpec.groovy
index a81b33bbd5..a882e31214 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/fileupload/FileUploadSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/fileupload/FileUploadSpec.groovy
@@ -18,38 +18,38 @@
  */
 package functionaltests.fileupload
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
 import groovy.json.JsonSlurper
+
 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 io.micronaut.http.client.exceptions.HttpClientResponseException
 import io.micronaut.http.client.multipart.MultipartBody
-import spock.lang.Specification
 import spock.lang.Shared
+import spock.lang.Specification
+
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for file upload functionality in Grails.
  * Tests various file upload patterns including single file, multiple files,
  * file validation, and metadata extraction.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class FileUploadSpec extends Specification {
 
     @Shared
     HttpClient client
 
     def setup() {
-        client = HttpClient.create(new URL("http://localhost:${serverPort}"))
+        client = client ?: HttpClient.create(new URL("http://localhost:${serverPort}"))
     }
 
-    def cleanup() {
-        client?.close()
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Single File Upload Tests ==========
@@ -62,7 +62,7 @@ class FileUploadSpec extends Specification {
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadSingle', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -104,7 +104,7 @@ class FileUploadSpec extends Specification {
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadWithMetadata', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -129,7 +129,7 @@ class FileUploadSpec extends Specification {
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadMultiple', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -157,7 +157,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadTextFile', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -180,7 +180,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadAndEcho', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -202,7 +202,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadWithValidation', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -222,7 +222,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadWithExtensionValidation', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -244,7 +244,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadWithExtensionValidation', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -266,7 +266,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/getFileInfo', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -289,7 +289,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/getFileInfo', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -312,7 +312,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadViaParams', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -336,7 +336,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadSingle', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -357,7 +357,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadAndEcho', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
@@ -379,7 +379,7 @@ This is a longer line with more words'''
             .build()
 
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/fileUploadTest/uploadAndEcho', body)
                 .contentType(MediaType.MULTIPART_FORM_DATA_TYPE),
             String
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/gorm/GormAdvancedSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/gorm/GormAdvancedSpec.groovy
index 2a70fd3930..2a20fe93b9 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/gorm/GormAdvancedSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/gorm/GormAdvancedSpec.groovy
@@ -16,14 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.gorm
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
 import spock.lang.Specification
-import spock.lang.Shared
+
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for advanced GORM features:
@@ -34,8 +32,8 @@ import spock.lang.Shared
  * - Named queries
  * - Detached criteria
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class GormAdvancedSpec extends Specification {
 
     def setup() {
@@ -43,7 +41,12 @@ class GormAdvancedSpec extends Specification {
         createTestData()
     }
 
-    private void createTestData() {
+    private static void createTestData() {
+
+        if (Author.count() > 0) {
+            return // Test data already exists
+        }
+
         // Author 1: American author with 3 books
         def author1 = new Author(name: 'John Smith', country: 'USA', birthYear: 1970, active: true)
         author1.addToBooks(new GormBook(title: 'The Great Adventure', genre: 'Fiction', price: 19.99, pageCount: 350, publicationYear: 2020, rating: 4.5))
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/i18n/InternationalizationSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/i18n/InternationalizationSpec.groovy
index 0570ede1aa..1c7a33e142 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/i18n/InternationalizationSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/i18n/InternationalizationSpec.groovy
@@ -16,15 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.i18n
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.client.HttpClient
+import spock.lang.Shared
 import spock.lang.Specification
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Comprehensive integration tests for internationalization (i18n) features.
  * 
@@ -38,19 +38,23 @@ import spock.lang.Specification
  * - Validation error messages
  * - Accept-Language header handling
  */
-@Integration(applicationClass = Application)
+@Integration
 class InternationalizationSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Basic Message Resolution Tests ==========
 
     def "test simple message in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessage?code=app.welcome&lang=en'),
@@ -62,15 +66,9 @@ class InternationalizationSpec extends Specification {
         response.body().code == 'app.welcome'
         response.body().locale == 'en'
         response.body().message == 'Welcome to the Application'
-
-        cleanup:
-        client.close()
     }
 
     def "test simple message in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessage?code=app.welcome&lang=de'),
@@ -82,15 +80,9 @@ class InternationalizationSpec extends Specification {
         response.body().code == 'app.welcome'
         response.body().locale == 'de'
         response.body().message == 'Willkommen in der Anwendung'
-
-        cleanup:
-        client.close()
     }
 
     def "test simple message in French"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessage?code=app.welcome&lang=fr'),
@@ -102,17 +94,11 @@ class InternationalizationSpec extends Specification {
         response.body().code == 'app.welcome'
         response.body().locale == 'fr'
         response.body().message == "Bienvenue dans l'application"
-
-        cleanup:
-        client.close()
     }
 
     // ========== Message With Arguments Tests ==========
 
     def "test message with argument in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessageWithArgs?code=app.greeting&arg=John&lang=en'),
@@ -122,15 +108,9 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Hello, John!'
-
-        cleanup:
-        client.close()
     }
 
     def "test message with argument in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessageWithArgs?code=app.greeting&arg=Johann&lang=de'),
@@ -140,15 +120,9 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Hallo, Johann!'
-
-        cleanup:
-        client.close()
     }
 
     def "test farewell message with argument"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessageWithArgs?code=app.farewell&arg=Alice&lang=en'),
@@ -158,17 +132,11 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Goodbye, Alice. See you soon!'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Pluralization Tests (Choice Format) ==========
 
     def "test choice format - zero items in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getChoiceMessage?count=0&lang=en'),
@@ -179,15 +147,9 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().count == 0
         response.body().message == 'You have no items.'
-
-        cleanup:
-        client.close()
     }
 
     def "test choice format - one item in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getChoiceMessage?count=1&lang=en'),
@@ -198,15 +160,9 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().count == 1
         response.body().message == 'You have one item.'
-
-        cleanup:
-        client.close()
     }
 
     def "test choice format - multiple items in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getChoiceMessage?count=5&lang=en'),
@@ -217,15 +173,9 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().count == 5
         response.body().message == 'You have 5 items.'
-
-        cleanup:
-        client.close()
     }
 
     def "test choice format in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getChoiceMessage?count=0&lang=de'),
@@ -235,15 +185,9 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Sie haben keine Artikel.'
-
-        cleanup:
-        client.close()
     }
 
     def "test choice format - one item in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getChoiceMessage?count=1&lang=de'),
@@ -253,17 +197,11 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Sie haben einen Artikel.'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Date Formatting Tests ==========
 
     def "test date formatting in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getDateMessage?lang=en'),
@@ -275,15 +213,9 @@ class InternationalizationSpec extends Specification {
         response.body().message.startsWith('Today is ')
         // English format: "Today is January 25, 2026."
         response.body().message.contains(',')
-
-        cleanup:
-        client.close()
     }
 
     def "test date formatting in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getDateMessage?lang=de'),
@@ -294,17 +226,11 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().message.startsWith('Heute ist der ')
         // German format: "Heute ist der 25. Januar 2026."
-
-        cleanup:
-        client.close()
     }
 
     // ========== Currency Formatting Tests ==========
 
     def "test currency formatting in English US"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getCurrencyMessage?amount=1234.56&lang=en_US'),
@@ -314,15 +240,9 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message.contains('$') || response.body().message.contains('1,234.56')
-
-        cleanup:
-        client.close()
     }
 
     def "test currency formatting in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getCurrencyMessage?amount=1234.56&lang=de_DE'),
@@ -333,17 +253,11 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         // German format uses € and different number formatting
         response.body().message != null
-
-        cleanup:
-        client.close()
     }
 
     // ========== Percentage Formatting Tests ==========
 
     def "test percentage formatting in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getPercentMessage?value=0.75&lang=en'),
@@ -354,17 +268,11 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().message.contains('75')
         response.body().message.contains('%')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Default Message Fallback Tests ==========
 
     def "test default message for non-existent code"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessageWithDefault?code=non.existent.key&defaultMsg=Fallback+Message&lang=en'),
@@ -374,17 +282,11 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Fallback Message'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Validation Messages Tests ==========
 
     def "test validation messages in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getValidationMessages?lang=en'),
@@ -397,15 +299,9 @@ class InternationalizationSpec extends Specification {
         response.body().messages.nullable.contains('cannot be null')
         response.body().messages.paginate_prev == 'Previous'
         response.body().messages.paginate_next == 'Next'
-
-        cleanup:
-        client.close()
     }
 
     def "test validation messages in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getValidationMessages?lang=de'),
@@ -416,15 +312,9 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().messages.paginate_prev == 'Vorherige'
         response.body().messages.paginate_next == 'Nächste'
-
-        cleanup:
-        client.close()
     }
 
     def "test validation messages in French"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getValidationMessages?lang=fr'),
@@ -435,17 +325,11 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().messages.paginate_prev == 'Précédent'
         response.body().messages.paginate_next == 'Suivant'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Multiple Messages Tests ==========
 
     def "test multiple messages at once in English"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMultipleMessages?lang=en'),
@@ -457,15 +341,9 @@ class InternationalizationSpec extends Specification {
         response.body().messages.welcome == 'Welcome to the Application'
         response.body().messages.greeting == 'Hello, User!'
         response.body().messages.farewell == 'Goodbye, User. See you soon!'
-
-        cleanup:
-        client.close()
     }
 
     def "test multiple messages at once in German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMultipleMessages?lang=de'),
@@ -477,17 +355,11 @@ class InternationalizationSpec extends Specification {
         response.body().messages.welcome == 'Willkommen in der Anwendung'
         response.body().messages.greeting == 'Hallo, User!'
         response.body().messages.farewell == 'Auf Wiedersehen, User. Bis bald!'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Locale Information Tests ==========
 
     def "test current locale information"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getCurrentLocale?lang=de_DE'),
@@ -498,17 +370,11 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().language == 'de'
         response.body().country == 'DE'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Accept-Language Header Tests ==========
 
     def "test locale from Accept-Language header - German"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getLocaleFromHeader')
@@ -520,15 +386,9 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         // The request locale should reflect the Accept-Language header
         response.body().requestLocale?.startsWith('de') || response.body().contextLocale?.startsWith('de')
-
-        cleanup:
-        client.close()
     }
 
     def "test locale from Accept-Language header - French"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getLocaleFromHeader')
@@ -539,17 +399,11 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().requestLocale?.startsWith('fr') || response.body().contextLocale?.startsWith('fr')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Controller Message Method Tests ==========
 
     def "test controller message method"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/useControllerMessage?code=app.welcome&lang=en'),
@@ -559,17 +413,11 @@ class InternationalizationSpec extends Specification {
         then:
         response.status.code == 200
         response.body().message == 'Welcome to the Application'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Edge Cases ==========
 
     def "test fallback to default locale when unsupported locale requested"() {
-        given:
-        def client = createClient()
-
         when: "requesting a locale that doesn't have translations"
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessage?code=app.welcome&lang=xyz'),
@@ -580,15 +428,9 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         // Will either get the message or fall back
         response.body().message != null
-
-        cleanup:
-        client.close()
     }
 
     def "test message with special characters"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/i18nTest/getMessageWithArgs?code=app.greeting&arg=%C3%A9l%C3%A8ve&lang=en'),
@@ -599,8 +441,5 @@ class InternationalizationSpec extends Specification {
         response.status.code == 200
         response.body().arg == 'élève'
         response.body().message == 'Hello, élève!'
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/interceptors/InterceptorOrderingSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/interceptors/InterceptorOrderingSpec.groovy
index da64200df5..acc1fcbfa4 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/interceptors/InterceptorOrderingSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/interceptors/InterceptorOrderingSpec.groovy
@@ -16,15 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.interceptors
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.client.HttpClient
+import spock.lang.Shared
 import spock.lang.Specification
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Comprehensive integration tests for Grails interceptor functionality.
  * 
@@ -37,32 +37,28 @@ import spock.lang.Specification
  * - Conditional matching
  * - Timing/performance tracking
  */
-@Integration(applicationClass = Application)
+@Integration
 class InterceptorOrderingSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
-    }
+    @Shared
+    HttpClient client
 
     def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
         // Reset execution order before each test
-        def client = createClient()
-        try {
-            client.toBlocking().exchange(
+        client.toBlocking().exchange(
                 HttpRequest.GET('/interceptorTest/resetOrder'),
                 Map
-            )
-        } finally {
-            client.close()
-        }
+        )
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Interceptor Ordering Tests ==========
 
     def "test interceptors execute in order by 'order' property"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/testOrder'),
@@ -88,15 +84,9 @@ class InterceptorOrderingSpec extends Specification {
         firstBeforeIdx < secondBeforeIdx
         secondBeforeIdx < thirdBeforeIdx
         thirdBeforeIdx < controllerIdx
-
-        cleanup:
-        client.close()
     }
 
     def "test before interceptors run before controller action"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/index'),
@@ -111,15 +101,9 @@ class InterceptorOrderingSpec extends Specification {
         order.findAll { it.contains(':before') }.every { beforeEntry ->
             order.indexOf(beforeEntry) < order.indexOf('controller:index')
         }
-
-        cleanup:
-        client.close()
     }
 
     def "test after interceptors run after controller action"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/index'),
@@ -134,17 +118,11 @@ class InterceptorOrderingSpec extends Specification {
         order.findAll { it.contains(':after') }.every { afterEntry ->
             order.indexOf(afterEntry) > order.indexOf('controller:index')
         }
-
-        cleanup:
-        client.close()
     }
 
     // ========== Blocking Interceptor Tests ==========
 
     def "test interceptor can block request by returning false"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/blocked?block=true&reason=testing'),
@@ -156,15 +134,9 @@ class InterceptorOrderingSpec extends Specification {
         response.body().blocked == true
         response.body().message == 'Request blocked by interceptor'
         response.body().reason == 'testing'
-
-        cleanup:
-        client.close()
     }
 
     def "test interceptor allows request when returning true"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/blocked?block=false'),
@@ -175,17 +147,11 @@ class InterceptorOrderingSpec extends Specification {
         response.status.code == 200
         response.body().action == 'blocked'
         response.body().message == 'This should not be seen if blocked'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Request Attribute Tests ==========
 
     def "test interceptor can set request attributes"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/checkAttributes'),
@@ -197,15 +163,9 @@ class InterceptorOrderingSpec extends Specification {
         response.body().fromBefore == true
         response.body().interceptorSet != null
         response.body().interceptorSet.source == 'AttributeSettingInterceptor'
-
-        cleanup:
-        client.close()
     }
 
     def "test interceptor can set response headers"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/checkAttributes'),
@@ -215,17 +175,11 @@ class InterceptorOrderingSpec extends Specification {
         then:
         response.status.code == 200
         response.header('X-Interceptor-Header') == 'set-by-interceptor'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Session Tests ==========
 
     def "test interceptor can set session attributes"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/checkSession'),
@@ -236,19 +190,11 @@ class InterceptorOrderingSpec extends Specification {
         response.status.code == 200
         response.body().sessionData != null
         response.body().sessionData.message == 'Session data from interceptor'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Conditional Matching Tests ==========
 
     def "test interceptor conditional matching - matched"() {
-        given:
-        def client = createClient()
-        // Reset first
-        client.toBlocking().exchange(HttpRequest.GET('/interceptorTest/resetOrder'), Map)
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/conditionalAction?match=yes'),
@@ -262,17 +208,9 @@ class InterceptorOrderingSpec extends Specification {
             Map
         )
         orderResponse.body().executionOrder.contains('conditional:before:matched')
-
-        cleanup:
-        client.close()
     }
 
     def "test interceptor conditional matching - not matched"() {
-        given:
-        def client = createClient()
-        // Reset first
-        client.toBlocking().exchange(HttpRequest.GET('/interceptorTest/resetOrder'), Map)
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/conditionalAction?match=no'),
@@ -286,19 +224,11 @@ class InterceptorOrderingSpec extends Specification {
             Map
         )
         orderResponse.body().executionOrder.contains('conditional:before:notmatched')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Timing Interceptor Tests ==========
 
     def "test timing interceptor tracks request duration"() {
-        given:
-        def client = createClient()
-        // Reset first
-        client.toBlocking().exchange(HttpRequest.GET('/interceptorTest/resetOrder'), Map)
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/slowAction?delay=50'),
@@ -317,19 +247,12 @@ class InterceptorOrderingSpec extends Specification {
         )
         orderResponse.body().executionOrder.any { it.startsWith('timing:before') }
         orderResponse.body().executionOrder.any { it.startsWith('timing:after') }
-
-        cleanup:
-        client.close()
     }
 
     // ========== Multiple Requests Tests ==========
 
     def "test interceptors work correctly across multiple requests"() {
-        given:
-        def client = createClient()
-
         when: "make multiple requests"
-        client.toBlocking().exchange(HttpRequest.GET('/interceptorTest/resetOrder'), Map)
         def response1 = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/index'),
             Map
@@ -349,17 +272,11 @@ class InterceptorOrderingSpec extends Specification {
         // Both should have similar execution patterns
         response1.body().executionOrder.contains('first:before')
         response2.body().executionOrder.contains('first:before')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Data Action Tests ==========
 
     def "test interceptors work with data actions"() {
-        given:
-        def client = createClient()
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/dataAction?data=testValue'),
@@ -369,18 +286,11 @@ class InterceptorOrderingSpec extends Specification {
         then:
         response.status.code == 200
         response.body().data == 'testValue'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Execution Order Verification ==========
 
     def "test complete before-controller-after sequence"() {
-        given:
-        def client = createClient()
-        client.toBlocking().exchange(HttpRequest.GET('/interceptorTest/resetOrder'), Map)
-
         when:
         def response = client.toBlocking().exchange(
             HttpRequest.GET('/interceptorTest/index'),
@@ -400,8 +310,5 @@ class InterceptorOrderingSpec extends Specification {
         beforeEntries.every { order.indexOf(it) < order.indexOf(controllerEntry) }
         // All afters come last
         afterEntries.every { order.indexOf(it) > order.indexOf(controllerEntry) }
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/requestresponse/RequestResponseSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/requestresponse/RequestResponseSpec.groovy
index 40f907bbad..d2c44d6c78 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/requestresponse/RequestResponseSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/requestresponse/RequestResponseSpec.groovy
@@ -18,36 +18,34 @@
  */
 package functionaltests.requestresponse
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
 import groovy.json.JsonSlurper
+
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.HttpResponse
 import io.micronaut.http.HttpStatus
-import io.micronaut.http.MutableHttpRequest
 import io.micronaut.http.client.HttpClient
 import io.micronaut.http.cookie.Cookie
-import spock.lang.Specification
 import spock.lang.Shared
+import spock.lang.Specification
+
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for request/response handling patterns including
  * headers, cookies, session management, and request attributes.
  */
-@Integration(applicationClass = Application)
-@Rollback
+@Integration
 class RequestResponseSpec extends Specification {
 
     @Shared
     HttpClient client
 
     def setup() {
-        client = HttpClient.create(new URL("http://localhost:${serverPort}"))
+        client = client ?: HttpClient.create(new URL("http://localhost:${serverPort}"))
     }
 
-    def cleanup() {
-        client?.close()
+    def cleanupSpec() {
+        client.close()
     }
 
     /**
@@ -63,7 +61,7 @@ class RequestResponseSpec extends Specification {
 
     def "echo request headers returns all headers"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/echoHeaders')
                 .header('X-Custom-Header', 'TestValue')
                 .header('X-Another-Header', 'AnotherValue'),
@@ -79,7 +77,7 @@ class RequestResponseSpec extends Specification {
 
     def "get specific header returns correct value"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/getSpecificHeader?headerName=X-Test-Header')
                 .header('X-Test-Header', 'MyTestValue'),
             String
@@ -94,7 +92,7 @@ class RequestResponseSpec extends Specification {
 
     def "check accept header detects JSON accept type"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/checkAcceptHeader')
                 .accept('application/json'),
             String
@@ -110,7 +108,7 @@ class RequestResponseSpec extends Specification {
 
     def "set custom headers returns headers in response"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setCustomHeaders'),
             String
         )
@@ -124,7 +122,7 @@ class RequestResponseSpec extends Specification {
 
     def "set cache headers configures caching properly"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setCacheHeaders'),
             String
         )
@@ -138,7 +136,7 @@ class RequestResponseSpec extends Specification {
 
     def "set no-cache headers prevents caching"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setNoCacheHeaders'),
             String
         )
@@ -152,7 +150,7 @@ class RequestResponseSpec extends Specification {
 
     def "set content disposition for file download"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setContentDisposition'),
             String
         )
@@ -164,7 +162,7 @@ class RequestResponseSpec extends Specification {
 
     def "set multiple custom headers returns all headers"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setMultipleCustomHeaders'),
             String
         )
@@ -180,7 +178,7 @@ class RequestResponseSpec extends Specification {
 
     def "set cookie returns Set-Cookie header"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setCookie?name=myCookie&value=myValue'),
             String
         )
@@ -196,7 +194,7 @@ class RequestResponseSpec extends Specification {
 
     def "set multiple cookies returns multiple Set-Cookie headers"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setMultipleCookies'),
             String
         )
@@ -210,7 +208,7 @@ class RequestResponseSpec extends Specification {
 
     def "get cookies reads cookies from request"() {
         when:
-        MutableHttpRequest<Object> request = HttpRequest.GET('/requestResponseTest/getCookies')
+        def request = HttpRequest.GET('/requestResponseTest/getCookies')
             .cookie(Cookie.of('testCookie1', 'value1'))
             .cookie(Cookie.of('testCookie2', 'value2'))
         HttpResponse<String> response = client.toBlocking().exchange(request, String)
@@ -224,7 +222,7 @@ class RequestResponseSpec extends Specification {
 
     def "get specific cookie returns correct cookie value"() {
         when:
-        MutableHttpRequest<Object> request = HttpRequest.GET('/requestResponseTest/getSpecificCookie?name=myCookie')
+        def request = HttpRequest.GET('/requestResponseTest/getSpecificCookie?name=myCookie')
             .cookie(Cookie.of('myCookie', 'cookieValue'))
         HttpResponse<String> response = client.toBlocking().exchange(request, String)
         def json = new JsonSlurper().parseText(response.body())
@@ -238,7 +236,7 @@ class RequestResponseSpec extends Specification {
 
     def "delete cookie sets max-age to 0"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/deleteCookie?name=deletedCookie'),
             String
         )
@@ -254,7 +252,7 @@ class RequestResponseSpec extends Specification {
 
     def "set session attribute stores value in session"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setSessionAttribute?key=testKey&value=testValue'),
             String
         )
@@ -270,7 +268,7 @@ class RequestResponseSpec extends Specification {
     def "get session attribute retrieves stored value"() {
         given:
         // First set a session attribute
-        HttpResponse<String> setResponse = client.toBlocking().exchange(
+        def setResponse = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setSessionAttribute?key=retrieveKey&value=retrieveValue'),
             String
         )
@@ -278,12 +276,12 @@ class RequestResponseSpec extends Specification {
 
         when:
         // Then retrieve it with the same session
-        MutableHttpRequest<Object> getRequest = HttpRequest.GET('/requestResponseTest/getSessionAttribute?key=retrieveKey')
+        def getRequest = HttpRequest.GET('/requestResponseTest/getSessionAttribute?key=retrieveKey')
         if (sessionCookie) {
             def cookieValue = sessionCookie.split(';')[0]
             getRequest = getRequest.header('Cookie', cookieValue)
         }
-        HttpResponse<String> response = client.toBlocking().exchange(getRequest, String)
+        def response = client.toBlocking().exchange(getRequest, String)
         def json = new JsonSlurper().parseText(response.body())
 
         then:
@@ -296,7 +294,7 @@ class RequestResponseSpec extends Specification {
     def "session counter increments on each request"() {
         given:
         // First request
-        HttpResponse<String> response1 = client.toBlocking().exchange(
+        def response1 = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/sessionCounter'),
             String
         )
@@ -305,12 +303,12 @@ class RequestResponseSpec extends Specification {
 
         when:
         // Second request with same session
-        MutableHttpRequest<Object> request2 = HttpRequest.GET('/requestResponseTest/sessionCounter')
+        def request2 = HttpRequest.GET('/requestResponseTest/sessionCounter')
         if (sessionCookie) {
             def cookieValue = sessionCookie.split(';')[0]
             request2 = request2.header('Cookie', cookieValue)
         }
-        HttpResponse<String> response2 = client.toBlocking().exchange(request2, String)
+        def response2 = client.toBlocking().exchange(request2, String)
         def json2 = new JsonSlurper().parseText(response2.body())
 
         then:
@@ -324,7 +322,7 @@ class RequestResponseSpec extends Specification {
 
     def "get request info returns server details"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/getRequestInfo'),
             String
         )
@@ -340,7 +338,7 @@ class RequestResponseSpec extends Specification {
 
     def "get request parameters returns query parameters"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/getRequestParameters?param1=value1&param2=value2'),
             String
         )
@@ -354,7 +352,7 @@ class RequestResponseSpec extends Specification {
 
     def "set request attribute stores and retrieves value"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/setRequestAttribute?key=myAttr&value=myVal'),
             String
         )
@@ -371,7 +369,7 @@ class RequestResponseSpec extends Specification {
 
     def "unicode response returns characters in multiple languages"() {
         when:
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/requestResponseTest/unicodeResponse'),
             String
         )
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/services/ServiceIntegrationSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/services/ServiceIntegrationSpec.groovy
index a2e414d48e..23b4a4f941 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/services/ServiceIntegrationSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/services/ServiceIntegrationSpec.groovy
@@ -16,23 +16,21 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.services
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
-import grails.gorm.transactions.Rollback
-import org.springframework.beans.factory.annotation.Autowired
 import spock.lang.Specification
-import spock.lang.Stepwise
+
+import org.springframework.beans.factory.annotation.Autowired
+
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for Grails services.
  * Tests transactional behavior, rollback scenarios, async operations,
  * and service dependency injection.
  */
-@Integration(applicationClass = Application)
-@Rollback
+@Integration
 class ServiceIntegrationSpec extends Specification {
 
     @Autowired
@@ -46,18 +44,22 @@ class ServiceIntegrationSpec extends Specification {
 
     // ========== Transactional Service Tests ==========
 
+    @Rollback
     def "service can add and retrieve product"() {
         when: "adding a product through the service"
         inventoryService.addProduct('SKU-001', 'Test Product', 29.99, 100)
 
-        then: "product can be retrieved"
+        and: "retrieving the product"
         def product = inventoryService.findBySku('SKU-001')
+
+        then: "the product was retrieved"
         product != null
         product.name == 'Test Product'
         product.price == 29.99
         product.quantity == 100
     }
 
+    @Rollback
     def "read-only transaction returns correct data"() {
         given: "multiple products exist"
         inventoryService.addProduct('CHEAP-001', 'Cheap Item', 5.00, 50)
@@ -72,6 +74,7 @@ class ServiceIntegrationSpec extends Specification {
         expensiveItems[0].sku == 'EXPENSIVE-001'
     }
 
+    // Do not use @Rollback here to test actual rollback behavior
     def "runtime exception causes transaction rollback"() {
         given: "initial count"
         def initialCount = inventoryService.countAll()
@@ -81,13 +84,10 @@ class ServiceIntegrationSpec extends Specification {
 
         then: "exception is thrown"
         thrown(RuntimeException)
-
-        // Note: Under @Rollback, the outer test transaction encompasses everything,
-        // so we verify the exception was thrown (which marks the transaction for rollback).
-        // The actual rollback happens at the end of the test method.
-        // To verify the service's rollback behavior in isolation, we'd need REQUIRES_NEW.
+        initialCount == inventoryService.countAll()
     }
 
+    @Rollback
     def "checked exception does NOT rollback by default"() {
         given: "initial count"
         def initialCount = inventoryService.countAll()
@@ -101,21 +101,23 @@ class ServiceIntegrationSpec extends Specification {
         and: "transaction is committed - product IS saved (default behavior)"
         // Note: This test documents default Spring behavior
         // Checked exceptions don't trigger rollback unless configured
-        inventoryService.countAll() >= initialCount
+        inventoryService.countAll() > initialCount
     }
 
+    // Do not use @Rollback here to test actual rollback behavior
     def "rollbackFor configuration causes rollback on checked exception"() {
+        given: "initial count"
+        def initialCount = inventoryService.countAll()
+
         when: "adding product with rollbackFor configured"
         inventoryService.addProductRollbackOnCheckedException('ROLLBACK-001', 'Should Rollback', 20.00, 7)
 
         then: "exception is thrown"
         thrown(Exception)
-
-        // Note: The rollbackFor annotation marks the transaction for rollback.
-        // Under @Rollback test context, the actual rollback happens at end of test.
-        // This test verifies the exception is properly thrown, which triggers the rollback.
+        inventoryService.countAll() == initialCount
     }
 
+    @Rollback
     def "update within transaction works correctly"() {
         given: "an existing product"
         inventoryService.addProduct('UPDATE-001', 'Update Test', 50.00, 100)
@@ -124,20 +126,22 @@ class ServiceIntegrationSpec extends Specification {
         def result = inventoryService.updateQuantity('UPDATE-001', 75)
 
         then: "update succeeds"
-        result == true
+        result
 
         and: "new quantity is persisted"
         inventoryService.findBySku('UPDATE-001').quantity == 75
     }
 
+    @Rollback
     def "update non-existent product returns false"() {
         when: "updating non-existent product"
         def result = inventoryService.updateQuantity('NONEXISTENT', 50)
 
         then: "update returns false"
-        result == false
+        !result
     }
 
+    @Rollback
     def "multi-entity transaction commits atomically"() {
         given: "two products with initial quantities"
         inventoryService.addProduct('FROM-001', 'Source Product', 10.00, 100)
@@ -151,6 +155,7 @@ class ServiceIntegrationSpec extends Specification {
         inventoryService.findBySku('TO-001').quantity == 80
     }
 
+    @Rollback
     def "multi-entity transaction rolls back on failure"() {
         given: "two products"
         inventoryService.addProduct('TRANSFER-FROM', 'Source', 10.00, 20)
@@ -167,6 +172,7 @@ class ServiceIntegrationSpec extends Specification {
         inventoryService.findBySku('TRANSFER-TO').quantity == 10
     }
 
+    @Rollback
     def "batch insert processes multiple items"() {
         given: "a list of items to insert"
         def items = [
@@ -185,6 +191,7 @@ class ServiceIntegrationSpec extends Specification {
         inventoryService.findBySku('BATCH-003') != null
     }
 
+    @Rollback
     def "delete removes product"() {
         given: "an existing product"
         inventoryService.addProduct('DELETE-001', 'To Delete', 5.00, 1)
@@ -194,12 +201,13 @@ class ServiceIntegrationSpec extends Specification {
         def result = inventoryService.deleteProduct('DELETE-001')
 
         then: "delete succeeds"
-        result == true
+        result
 
         and: "product no longer exists"
         inventoryService.findBySku('DELETE-001') == null
     }
 
+    @Rollback
     def "total inventory value calculation"() {
         given: "products with known values"
         inventoryService.addProduct('VALUE-001', 'Item 1', 10.00, 5)   // 50.00
@@ -221,6 +229,7 @@ class ServiceIntegrationSpec extends Specification {
         orderService.applicationContext != null
     }
 
+    @Rollback
     def "order service uses inventory service"() {
         given: "product in inventory"
         inventoryService.addProduct('ORDER-001', 'Orderable Item', 49.99, 50)
@@ -239,6 +248,7 @@ class ServiceIntegrationSpec extends Specification {
         inventoryService.findBySku('ORDER-001').quantity == 45
     }
 
+    @Rollback
     def "order fails for non-existent product"() {
         when: "ordering non-existent product"
         def result = orderService.placeOrder('NONEXISTENT', 1)
@@ -248,6 +258,7 @@ class ServiceIntegrationSpec extends Specification {
         result.error == 'Product not found'
     }
 
+    @Rollback
     def "order fails for insufficient stock"() {
         given: "product with limited stock"
         inventoryService.addProduct('LIMITED-001', 'Limited Stock', 100.00, 3)
@@ -262,6 +273,7 @@ class ServiceIntegrationSpec extends Specification {
         result.requested == 10
     }
 
+    @Rollback
     def "get quote returns pricing without modifying inventory"() {
         given: "product in inventory"
         inventoryService.addProduct('QUOTE-001', 'Quotable Item', 75.00, 20)
@@ -281,9 +293,9 @@ class ServiceIntegrationSpec extends Specification {
 
     def "service can check bean availability"() {
         expect: "known services are available"
-        orderService.isServiceAvailable('inventoryService') == true
-        orderService.isServiceAvailable('asyncProcessingService') == true
-        orderService.isServiceAvailable('nonExistentService') == false
+        orderService.isServiceAvailable('inventoryService')
+        orderService.isServiceAvailable('asyncProcessingService')
+        !orderService.isServiceAvailable('nonExistentService')
     }
 
     def "service can retrieve beans dynamically"() {
@@ -325,6 +337,7 @@ class ServiceIntegrationSpec extends Specification {
         result == ['cba', 'fed', 'ihg']
     }
 
+    @Rollback
     def "async method can access database"() {
         given: "products in database"
         inventoryService.addProduct('ASYNC-001', 'Async Test 1', 10.00, 5)
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/springevents/SpringEventsSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/springevents/SpringEventsSpec.groovy
index 01262944bf..94fe5deb5e 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/springevents/SpringEventsSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/springevents/SpringEventsSpec.groovy
@@ -16,28 +16,28 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.springevents
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import groovy.json.JsonSlurper
+
 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 org.springframework.beans.factory.annotation.Autowired
 import spock.lang.Narrative
+import spock.lang.Shared
 import spock.lang.Specification
 
+import org.springframework.beans.factory.annotation.Autowired
+
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for Spring application events in Grails.
  * 
  * Tests event publishing, listening, conditional handling,
  * ordered listeners, and event payloads.
  */
-@Integration(applicationClass = Application)
+@Integration
 @Narrative('''
 Spring's ApplicationEvent mechanism allows decoupled communication between
 components. Grails integrates with Spring events via @EventListener annotations
@@ -51,31 +51,35 @@ class SpringEventsSpec extends Specification {
     @Autowired
     EventPublisherService eventPublisherService
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
-    }
+    @Shared
+    HttpClient client
 
     def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
         eventListenerService.clearEvents()
     }
 
+    def cleanupSpec() {
+        client.close()
+    }
+
     // ========== Basic Event Publishing ==========
 
     def "custom event is published and received"() {
         when: "publishing a custom event"
-        eventPublisherService.publishCustomEvent("Test Message", [key: "value"])
+        eventPublisherService.publishCustomEvent('Test Message', [key: 'value'])
 
         then: "event is received by listener"
         eventListenerService.eventCount == 1
         eventListenerService.customEvents.size() == 1
-        eventListenerService.customEvents[0].message == "Test Message"
-        eventListenerService.customEvents[0].payload.key == "value"
+        eventListenerService.customEvents[0].message == 'Test Message'
+        eventListenerService.customEvents[0].payload.key == 'value'
     }
 
     def "event createdAt is set"() {
         when: "publishing an event"
         def before = new Date()
-        eventPublisherService.publishCustomEvent("Timestamp Test")
+        eventPublisherService.publishCustomEvent('Timestamp Test')
         def after = new Date()
 
         then: "createdAt is within expected range"
@@ -85,13 +89,13 @@ class SpringEventsSpec extends Specification {
 
     def "user action event is published and received"() {
         when: "publishing a user action event"
-        eventPublisherService.publishUserAction("user-123", "LOGIN", [ip: "192.168.1.1"])
+        eventPublisherService.publishUserAction('user-123', 'LOGIN', [ip: '192.168.1.1'])
 
         then: "event is received with correct data"
         eventListenerService.userActionEvents.size() == 1
-        eventListenerService.userActionEvents[0].userId == "user-123"
-        eventListenerService.userActionEvents[0].action == "LOGIN"
-        eventListenerService.userActionEvents[0].metadata.ip == "192.168.1.1"
+        eventListenerService.userActionEvents[0].userId == 'user-123'
+        eventListenerService.userActionEvents[0].action == 'LOGIN'
+        eventListenerService.userActionEvents[0].metadata.ip == '192.168.1.1'
     }
 
     // ========== Multiple Events ==========
@@ -105,16 +109,16 @@ class SpringEventsSpec extends Specification {
         eventListenerService.customEvents.size() == 5
         
         and: "events have correct sequence"
-        eventListenerService.customEvents[0].message == "Event #1"
-        eventListenerService.customEvents[4].message == "Event #5"
+        eventListenerService.customEvents[0].message == 'Event #1'
+        eventListenerService.customEvents[4].message == 'Event #5'
     }
 
     def "events from different types are tracked separately"() {
         when: "publishing different event types"
-        eventPublisherService.publishCustomEvent("Custom 1")
-        eventPublisherService.publishUserAction("user1", "ACTION1")
-        eventPublisherService.publishCustomEvent("Custom 2")
-        eventPublisherService.publishUserAction("user2", "ACTION2")
+        eventPublisherService.publishCustomEvent('Custom 1')
+        eventPublisherService.publishUserAction('user1', 'ACTION1')
+        eventPublisherService.publishCustomEvent('Custom 2')
+        eventPublisherService.publishUserAction('user2', 'ACTION2')
 
         then: "events are tracked by type"
         eventListenerService.customEvents.size() == 2
@@ -126,41 +130,38 @@ class SpringEventsSpec extends Specification {
 
     def "event listeners are executed in order"() {
         when: "publishing a priority event"
-        eventPublisherService.publishPriorityEvent(1, "test")
+        eventPublisherService.publishPriorityEvent(1, 'test')
 
         then: "listeners execute in @Order sequence"
         eventListenerService.orderedResults.size() == 3
-        eventListenerService.orderedResults[0] == "first-test"
-        eventListenerService.orderedResults[1] == "second-test"
-        eventListenerService.orderedResults[2] == "third-test"
+        eventListenerService.orderedResults[0] == 'first-test'
+        eventListenerService.orderedResults[1] == 'second-test'
+        eventListenerService.orderedResults[2] == 'third-test'
     }
 
     // ========== Conditional Event Listeners ==========
 
     def "conditional listener handles matching events"() {
         when: "publishing event that matches condition"
-        eventPublisherService.publishCustomEvent("IMPORTANT: Critical Alert", [:])
+        eventPublisherService.publishCustomEvent('IMPORTANT: Critical Alert', [:])
 
         then: "conditional handler is triggered"
-        eventListenerService.conditionalResults.any { it.startsWith("CONDITIONAL:IMPORTANT") }
+        eventListenerService.conditionalResults.any { it.startsWith('CONDITIONAL:IMPORTANT') }
     }
 
     def "conditional listener ignores non-matching events"() {
         when: "publishing event that doesn't match condition"
-        eventPublisherService.publishCustomEvent("NORMAL: Regular message", [:])
+        eventPublisherService.publishCustomEvent('NORMAL: Regular message', [:])
 
         then: "conditional handler is not triggered"
-        !eventListenerService.conditionalResults.any { it.startsWith("CONDITIONAL:") }
+        !eventListenerService.conditionalResults.any { it.startsWith('CONDITIONAL:') }
     }
 
     // ========== Event Publishing via HTTP ==========
 
     def "event can be published via HTTP endpoint"() {
-        given:
-        def client = createClient()
-
         when: "calling publish endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishCustom?message=HTTP+Event'),
             String
         )
@@ -169,18 +170,12 @@ class SpringEventsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.published == true
-        json.message == "HTTP Event"
-
-        cleanup:
-        client.close()
+        json.message == 'HTTP Event'
     }
 
     def "user action event can be published via HTTP"() {
-        given:
-        def client = createClient()
-
         when: "calling user action publish endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishUserAction?userId=web-user&userAction=CLICK'),
             String
         )
@@ -189,19 +184,13 @@ class SpringEventsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.published == true
-        json.userId == "web-user"
-        json.userAction == "CLICK"
-
-        cleanup:
-        client.close()
+        json.userId == 'web-user'
+        json.userAction == 'CLICK'
     }
 
     def "priority event ordering works via HTTP"() {
-        given:
-        def client = createClient()
-
         when: "calling priority publish endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishPriority?data=http-test'),
             String
         )
@@ -210,18 +199,12 @@ class SpringEventsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.orderedResults.size() == 3
-        json.orderedResults[0] == "first-http-test"
-
-        cleanup:
-        client.close()
+        json.orderedResults[0] == 'first-http-test'
     }
 
     def "multiple events can be published via HTTP"() {
-        given:
-        def client = createClient()
-
         when: "calling multiple publish endpoint"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishMultiple?count=3'),
             String
         )
@@ -231,17 +214,11 @@ class SpringEventsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.count == 3
         json.receivedCount == 3
-
-        cleanup:
-        client.close()
     }
 
     def "conditional event works via HTTP for matching message"() {
-        given:
-        def client = createClient()
-
         when: "publishing important message"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishConditional?important=true'),
             String
         )
@@ -249,18 +226,12 @@ class SpringEventsSpec extends Specification {
         then: "conditional handler triggers"
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
-        json.conditionalResults.any { it.startsWith("CONDITIONAL:") }
-
-        cleanup:
-        client.close()
+        json.conditionalResults.any { it.startsWith('CONDITIONAL:') }
     }
 
     def "conditional event skipped via HTTP for non-matching message"() {
-        given:
-        def client = createClient()
-
         when: "publishing normal message"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishConditional?important=false'),
             String
         )
@@ -268,23 +239,19 @@ class SpringEventsSpec extends Specification {
         then: "conditional handler does not trigger"
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
-        !json.conditionalResults.any { it.toString().startsWith("CONDITIONAL:") }
-
-        cleanup:
-        client.close()
+        !json.conditionalResults.any { it.toString().startsWith('CONDITIONAL:') }
     }
 
     // ========== Event Stats ==========
 
     def "event stats are accessible via HTTP"() {
         given:
-        def client = createClient()
-        eventPublisherService.publishCustomEvent("Stats Test 1")
-        eventPublisherService.publishCustomEvent("Stats Test 2")
-        eventPublisherService.publishUserAction("user", "action")
+        eventPublisherService.publishCustomEvent('Stats Test 1')
+        eventPublisherService.publishCustomEvent('Stats Test 2')
+        eventPublisherService.publishUserAction('user', 'action')
 
         when: "getting stats"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/stats'),
             String
         )
@@ -295,20 +262,16 @@ class SpringEventsSpec extends Specification {
         json.totalEvents == 3
         json.customEvents == 2
         json.userActionEvents == 1
-
-        cleanup:
-        client.close()
     }
 
     // ========== Clear Events ==========
 
     def "events can be cleared via HTTP"() {
         given:
-        def client = createClient()
-        eventPublisherService.publishCustomEvent("To be cleared")
+        eventPublisherService.publishCustomEvent('To be cleared')
 
         when: "clearing events"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/clearEvents'),
             String
         )
@@ -316,19 +279,13 @@ class SpringEventsSpec extends Specification {
         then: "events are cleared"
         response.status == HttpStatus.OK
         eventListenerService.eventCount == 0
-
-        cleanup:
-        client.close()
     }
 
     // ========== Transactional Event Publishing ==========
 
     def "event can be published in transactional context"() {
-        given:
-        def client = createClient()
-
         when: "publishing transactional event"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/springEvent/publishTransactional?message=tx-test'),
             String
         )
@@ -339,10 +296,7 @@ class SpringEventsSpec extends Specification {
         json.published == true
         
         and: "event is received"
-        eventListenerService.customEvents.any { it.message.contains("tx-test") }
-
-        cleanup:
-        client.close()
+        eventListenerService.customEvents.any { it.message.contains('tx-test') }
     }
 
     // ========== Event Payload Tests ==========
@@ -354,22 +308,22 @@ class SpringEventsSpec extends Specification {
                 list: [1, 2, 3],
                 map: [a: 'b', c: 'd']
             ],
-            string: "value",
+            string: 'value',
             number: 42
         ]
-        eventPublisherService.publishCustomEvent("Complex Payload", payload)
+        eventPublisherService.publishCustomEvent('Complex Payload', payload)
 
         then: "payload is preserved"
         def event = eventListenerService.customEvents[0]
         event.payload.nested.list == [1, 2, 3]
         event.payload.nested.map.a == 'b'
-        event.payload.string == "value"
+        event.payload.string == 'value'
         event.payload.number == 42
     }
 
     def "event payload handles null values"() {
         when: "publishing event with null in payload"
-        eventPublisherService.publishCustomEvent("Null Payload", [key: null])
+        eventPublisherService.publishCustomEvent('Null Payload', [key: null])
 
         then: "null is preserved"
         def event = eventListenerService.customEvents[0]
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/taglib/TagLibSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/taglib/TagLibSpec.groovy
index 419f82860b..d81c17169f 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/taglib/TagLibSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/taglib/TagLibSpec.groovy
@@ -16,74 +16,66 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.taglib
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import io.micronaut.http.HttpRequest
 import io.micronaut.http.client.HttpClient
+import spock.lang.Shared
 import spock.lang.Specification
 import spock.lang.Unroll
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for GSP Tag Libraries.
  * Tests both custom tag libraries and built-in Grails tags.
  */
-@Integration(applicationClass = Application)
+@Integration
 class TagLibSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Custom Tag: hello ==========
 
     def "custom:hello tag renders greeting with name attribute"() {
-        given: "a request with a name parameter"
-        def client = createClient()
-
         when: "calling the hello tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testHelloTag?name=Grails"),
+            HttpRequest.GET('/tagLibTest/testHelloTag?name=Grails'),
             String
         )
 
         then: "greeting is rendered with the name"
         response.status.code == 200
         response.body().contains('Hello, Grails!')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:hello tag uses default name when not provided"() {
-        given: "a request without a name parameter"
-        def client = createClient()
-
         when: "calling the hello tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testHelloTag"),
+            HttpRequest.GET('/tagLibTest/testHelloTag'),
             String
         )
 
         then: "greeting is rendered with default name"
         response.status.code == 200
         response.body().contains('Hello, World!')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: wrapper ==========
 
     def "custom:wrapper tag renders title and body content"() {
-        given: "a request with title and content"
-        def client = createClient()
-
         when: "calling the wrapper tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testWrapperTag?title=My%20Section&content=Section%20content"),
+            HttpRequest.GET('/tagLibTest/testWrapperTag?title=My%20Section&content=Section%20content'),
             String
         )
 
@@ -93,38 +85,26 @@ class TagLibSpec extends Specification {
         body.contains('<div class="wrapper">')
         body.contains('<h2>My Section</h2>')
         body.contains('Section content')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:wrapper tag applies custom CSS class"() {
-        given: "a request with custom CSS class"
-        def client = createClient()
-
         when: "calling the wrapper tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testWrapperTag?title=Test&content=Test&cssClass=custom-wrapper"),
+            HttpRequest.GET('/tagLibTest/testWrapperTag?title=Test&content=Test&cssClass=custom-wrapper'),
             String
         )
 
         then: "custom CSS class is applied"
         response.status.code == 200
         response.body().contains('<div class="custom-wrapper">')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: iterate ==========
 
     def "custom:iterate tag iterates over items"() {
-        given: "a request with items"
-        def client = createClient()
-
         when: "calling the iterate tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testIterateTag?items=A,B,C"),
+            HttpRequest.GET('/tagLibTest/testIterateTag?items=A,B,C'),
             String
         )
 
@@ -134,18 +114,12 @@ class TagLibSpec extends Specification {
         body.contains('Item: A')
         body.contains('Item: B')
         body.contains('Item: C')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:iterate tag uses separator between items"() {
-        given: "a request with separator"
-        def client = createClient()
-
         when: "calling the iterate tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testIterateTag?items=X,Y,Z&separator=-"),
+            HttpRequest.GET('/tagLibTest/testIterateTag?items=X,Y,Z&separator=-'),
             String
         )
 
@@ -153,20 +127,14 @@ class TagLibSpec extends Specification {
         response.status.code == 200
         def body = response.body()
         body.contains('Item: X-Item: Y-Item: Z')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: showIf/hideIf ==========
 
     def "custom:showIf tag shows content when condition is true"() {
-        given: "a request with true condition"
-        def client = createClient()
-
         when: "calling the conditional tags test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testConditionalTags?condition=true"),
+            HttpRequest.GET('/tagLibTest/testConditionalTags?condition=true'),
             String
         )
 
@@ -175,18 +143,12 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('id="showIf-result">VISIBLE')
         !body.contains('id="hideIf-result">HIDDEN')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:hideIf tag shows content when condition is false"() {
-        given: "a request with false condition"
-        def client = createClient()
-
         when: "calling the conditional tags test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testConditionalTags?condition=false"),
+            HttpRequest.GET('/tagLibTest/testConditionalTags?condition=false'),
             String
         )
 
@@ -195,18 +157,12 @@ class TagLibSpec extends Specification {
         def body = response.body()
         !body.contains('id="showIf-result">VISIBLE')
         body.contains('id="hideIf-result">HIDDEN')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: formatted ==========
 
     @Unroll
     def "custom:formatted tag formats value as #format"() {
-        given: "a request with format parameters"
-        def client = createClient()
-
         when: "calling the formatted tag test endpoint"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/tagLibTest/testFormattedTag?value=${value}&format=${format}&decimals=${decimals}"),
@@ -217,9 +173,6 @@ class TagLibSpec extends Specification {
         response.status.code == 200
         response.body().contains(expected)
 
-        cleanup:
-        client.close()
-
         where:
         value    | format       | decimals | expected
         100.0    | 'currency'   | 2        | '$100.00'
@@ -230,12 +183,9 @@ class TagLibSpec extends Specification {
     // ========== Custom Tag: list ==========
 
     def "custom:list tag renders unordered list by default"() {
-        given: "a request with items"
-        def client = createClient()
-
         when: "calling the list tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testListTag?items=Apple,Banana,Cherry"),
+            HttpRequest.GET('/tagLibTest/testListTag?items=Apple,Banana,Cherry'),
             String
         )
 
@@ -247,18 +197,12 @@ class TagLibSpec extends Specification {
         body.contains('<li>Banana</li>')
         body.contains('<li>Cherry</li>')
         body.contains('</ul>')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:list tag renders ordered list when type is ordered"() {
-        given: "a request with ordered type"
-        def client = createClient()
-
         when: "calling the list tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testListTag?items=First,Second,Third&type=ordered"),
+            HttpRequest.GET('/tagLibTest/testListTag?items=First,Second,Third&type=ordered'),
             String
         )
 
@@ -267,20 +211,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('<ol>')
         body.contains('</ol>')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: panel ==========
 
     def "custom:panel tag renders panel with title and body"() {
-        given: "a request with panel parameters"
-        def client = createClient()
-
         when: "calling the panel tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testPanelTag?title=Info%20Panel&type=info&content=Panel%20content"),
+            HttpRequest.GET('/tagLibTest/testPanelTag?title=Info%20Panel&type=info&content=Panel%20content'),
             String
         )
 
@@ -292,36 +230,24 @@ class TagLibSpec extends Specification {
         body.contains('<h3>Info Panel</h3>')
         body.contains('class="panel-body"')
         body.contains('Panel content')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:panel tag renders collapse button when collapsible"() {
-        given: "a request with collapsible panel"
-        def client = createClient()
-
         when: "calling the panel tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testPanelTag?title=Collapsible&collapsible=true"),
+            HttpRequest.GET('/tagLibTest/testPanelTag?title=Collapsible&collapsible=true'),
             String
         )
 
         then: "collapse button is rendered"
         response.status.code == 200
         response.body().contains('class="collapse-btn"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: badge ==========
 
     @Unroll
     def "custom:badge tag renders badge with type=#type and size=#size"() {
-        given: "a request with badge parameters"
-        def client = createClient()
-
         when: "calling the badge tag test endpoint"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/tagLibTest/testBadgeTag?type=${type}&size=${size}&content=${content}"),
@@ -335,9 +261,6 @@ class TagLibSpec extends Specification {
         body.contains("badge-${size}")
         body.contains(">${content}<")
 
-        cleanup:
-        client.close()
-
         where:
         type      | size    | content
         'success' | 'small' | '10'
@@ -348,12 +271,9 @@ class TagLibSpec extends Specification {
     // ========== Custom Tag: progress ==========
 
     def "custom:progress tag renders progress bar with percentage"() {
-        given: "a request with progress parameters"
-        def client = createClient()
-
         when: "calling the progress tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testProgressTag?value=75&max=100"),
+            HttpRequest.GET('/tagLibTest/testProgressTag?value=75&max=100'),
             String
         )
 
@@ -364,18 +284,12 @@ class TagLibSpec extends Specification {
         body.contains('class="progress-bar"')
         body.contains('style="width: 75%"')
         body.contains('75%')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:progress tag hides label when showLabel is false"() {
-        given: "a request with showLabel=false"
-        def client = createClient()
-
         when: "calling the progress tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testProgressTag?value=50&max=100&showLabel=false"),
+            HttpRequest.GET('/tagLibTest/testProgressTag?value=50&max=100&showLabel=false'),
             String
         )
 
@@ -384,20 +298,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('class="progress-bar"')
         !body.contains('>50%<')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: repeat ==========
 
     def "custom:repeat tag repeats body content specified times"() {
-        given: "a request with times parameter"
-        def client = createClient()
-
         when: "calling the repeat tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testRepeatTag?times=3"),
+            HttpRequest.GET('/tagLibTest/testRepeatTag?times=3'),
             String
         )
 
@@ -407,58 +315,40 @@ class TagLibSpec extends Specification {
         body.contains('Repeat #1')
         body.contains('Repeat #2')
         body.contains('Repeat #3')
-
-        cleanup:
-        client.close()
     }
 
     def "custom:repeat tag uses separator between repetitions"() {
-        given: "a request with separator"
-        def client = createClient()
-
         when: "calling the repeat tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testRepeatTag?times=2&separator=%20-%20"),
+            HttpRequest.GET('/tagLibTest/testRepeatTag?times=2&separator=%20-%20'),
             String
         )
 
         then: "repetitions are separated"
         response.status.code == 200
         response.body().contains('Repeat #1 - Repeat #2')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: raw ==========
 
     def "custom:raw tag outputs unescaped HTML content"() {
-        given: "a request with HTML content"
-        def client = createClient()
-
         when: "calling the raw tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testRawTag"),
+            HttpRequest.GET('/tagLibTest/testRawTag'),
             String
         )
 
         then: "HTML content is not escaped"
         response.status.code == 200
         response.body().contains('<strong>Bold Text</strong>')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: definitionList ==========
 
     def "custom:definitionList tag renders definition list from map"() {
-        given: "a request to test definition list"
-        def client = createClient()
-
         when: "calling the definition list tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testDefinitionListTag"),
+            HttpRequest.GET('/tagLibTest/testDefinitionListTag'),
             String
         )
 
@@ -471,78 +361,54 @@ class TagLibSpec extends Specification {
         body.contains('<dt>age</dt>')
         body.contains('<dd>30</dd>')
         body.contains('</dl>')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: requestInfo ==========
 
     def "custom:requestInfo tag retrieves request attributes"() {
-        given: "a request to test request info"
-        def client = createClient()
-
         when: "calling the request info tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testRequestInfoTag?attr=method"),
+            HttpRequest.GET('/tagLibTest/testRequestInfoTag?attr=method'),
             String
         )
 
         then: "request attribute is output"
         response.status.code == 200
         response.body().contains('GET')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: sessionValue ==========
 
     def "custom:sessionValue tag displays default when session value not set"() {
-        given: "a request without session value"
-        def client = createClient()
-
         when: "calling the session value tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testSessionValueTag?key=nonexistent&default=DefaultUser"),
+            HttpRequest.GET('/tagLibTest/testSessionValueTag?key=nonexistent&default=DefaultUser'),
             String
         )
 
         then: "default value is displayed"
         response.status.code == 200
         response.body().contains('DefaultUser')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: setVar ==========
 
     def "custom:setVar tag sets pageScope variable"() {
-        given: "a request to set a variable"
-        def client = createClient()
-
         when: "calling the setVar tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testSetVarTag?varName=testVar&varValue=TestValue"),
+            HttpRequest.GET('/tagLibTest/testSetVarTag?varName=testVar&varValue=TestValue'),
             String
         )
 
         then: "variable is set and accessible"
         response.status.code == 200
         response.body().contains('Variable testVar = TestValue')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: alert ==========
 
     @Unroll
     def "custom:alert tag renders #type alert"() {
-        given: "a request with alert parameters"
-        def client = createClient()
-
         when: "calling the alert tag test endpoint"
         def response = client.toBlocking().exchange(
             HttpRequest.GET("/tagLibTest/testAlertTag?type=${type}&message=${URLEncoder.encode(message, 'UTF-8')}"),
@@ -555,9 +421,6 @@ class TagLibSpec extends Specification {
         body.contains("alert-${type}")
         body.contains(message)
 
-        cleanup:
-        client.close()
-
         where:
         type      | message
         'info'    | 'InfoMessage'
@@ -567,12 +430,9 @@ class TagLibSpec extends Specification {
     }
 
     def "custom:alert tag renders dismissible button when dismissible=true"() {
-        given: "a request with dismissible alert"
-        def client = createClient()
-
         when: "calling the alert tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testAlertTag?type=info&dismissible=true"),
+            HttpRequest.GET('/tagLibTest/testAlertTag?type=info&dismissible=true'),
             String
         )
 
@@ -581,40 +441,28 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('alert-dismissible')
         body.contains('class="close"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: join ==========
 
     def "custom:join tag joins items with separator"() {
-        given: "a request with items to join"
-        def client = createClient()
-
         when: "calling the join tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testJoinTag?items=red,green,blue&separator=-"),
+            HttpRequest.GET('/tagLibTest/testJoinTag?items=red,green,blue&separator=-'),
             String
         )
 
         then: "items are joined with separator"
         response.status.code == 200
         response.body().contains('red-green-blue')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Custom Tag: cssClass ==========
 
     def "custom:cssClass tag builds class string from boolean attributes"() {
-        given: "a request with CSS class parameters"
-        def client = createClient()
-
         when: "calling the cssClass tag test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testCssClassTag?base=btn&active=true&disabled=false&highlighted=true"),
+            HttpRequest.GET('/tagLibTest/testCssClassTag?base=btn&active=true&disabled=false&highlighted=true'),
             String
         )
 
@@ -625,20 +473,14 @@ class TagLibSpec extends Specification {
         body.contains('active')
         body.contains('highlighted')
         !body.contains('disabled')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:if ==========
 
     def "g:if tag shows content when condition is true"() {
-        given: "a request with a value greater than 5"
-        def client = createClient()
-
         when: "calling the built-in if test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInIf?value=10"),
+            HttpRequest.GET('/tagLibTest/testBuiltInIf?value=10'),
             String
         )
 
@@ -647,38 +489,26 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('Greater than 5')
         !body.contains('Less than 5')
-
-        cleanup:
-        client.close()
     }
 
     def "g:elseif and g:else work correctly"() {
-        given: "a request with a value of 30"
-        def client = createClient()
-
         when: "calling the built-in if test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInIf?value=30"),
+            HttpRequest.GET('/tagLibTest/testBuiltInIf?value=30'),
             String
         )
 
         then: "elseif content is shown"
         response.status.code == 200
         response.body().contains('Over 20')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:each ==========
 
     def "g:each tag iterates over collection"() {
-        given: "a request with items"
-        def client = createClient()
-
         when: "calling the built-in each test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInEach?items=A,B,C"),
+            HttpRequest.GET('/tagLibTest/testBuiltInEach?items=A,B,C'),
             String
         )
 
@@ -688,18 +518,12 @@ class TagLibSpec extends Specification {
         body.contains('[A]')
         body.contains('[B]')
         body.contains('[C]')
-
-        cleanup:
-        client.close()
     }
 
     def "g:each tag provides status variable"() {
-        given: "a request with items"
-        def client = createClient()
-
         when: "calling the built-in each test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInEach?items=X,Y,Z"),
+            HttpRequest.GET('/tagLibTest/testBuiltInEach?items=X,Y,Z'),
             String
         )
 
@@ -709,20 +533,14 @@ class TagLibSpec extends Specification {
         body.contains('0:X')
         body.contains('1:Y')
         body.contains('2:Z')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:collect ==========
 
     def "g:collect tag transforms items"() {
-        given: "a request with items"
-        def client = createClient()
-
         when: "calling the built-in collect test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInCollect?items=apple,banana"),
+            HttpRequest.GET('/tagLibTest/testBuiltInCollect?items=apple,banana'),
             String
         )
 
@@ -731,20 +549,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('APPLE')
         body.contains('BANANA')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:findAll ==========
 
     def "g:findAll tag filters items"() {
-        given: "a request with threshold"
-        def client = createClient()
-
         when: "calling the built-in findAll test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInFindAll?threshold=7"),
+            HttpRequest.GET('/tagLibTest/testBuiltInFindAll?threshold=7'),
             String
         )
 
@@ -755,20 +567,14 @@ class TagLibSpec extends Specification {
         body.contains('9')
         body.contains('10')
         !body.contains('7 ')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:link ==========
 
     def "g:link tag creates link with controller and action"() {
-        given: "a request to create a link"
-        def client = createClient()
-
         when: "calling the built-in link test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInLink?targetController=book&targetAction=show&targetId=42&linkText=View"),
+            HttpRequest.GET('/tagLibTest/testBuiltInLink?targetController=book&targetAction=show&targetId=42&linkText=View'),
             String
         )
 
@@ -778,40 +584,28 @@ class TagLibSpec extends Specification {
         body.contains('<a href=')
         body.contains('/book/show/42')
         body.contains('>View</a>')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:createLink ==========
 
     def "g:createLink tag creates URL string"() {
-        given: "a request to create a link URL"
-        def client = createClient()
-
         when: "calling the built-in createLink test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInCreateLink?targetController=book&targetAction=list"),
+            HttpRequest.GET('/tagLibTest/testBuiltInCreateLink?targetController=book&targetAction=list'),
             String
         )
 
         then: "URL is rendered"
         response.status.code == 200
         response.body().contains('/book/list')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:form ==========
 
     def "g:form tag creates form with action"() {
-        given: "a request to create a form"
-        def client = createClient()
-
         when: "calling the built-in form test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInForm?targetController=book&targetAction=save"),
+            HttpRequest.GET('/tagLibTest/testBuiltInForm?targetController=book&targetAction=save'),
             String
         )
 
@@ -822,40 +616,28 @@ class TagLibSpec extends Specification {
         body.contains('action=')
         body.contains('/book/save')
         body.contains('method="post"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:message ==========
 
     def "g:message tag renders message with default"() {
-        given: "a request with message code"
-        def client = createClient()
-
         when: "calling the built-in message test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInMessage?code=nonexistent.key&default=Default%20Message"),
+            HttpRequest.GET('/tagLibTest/testBuiltInMessage?code=nonexistent.key&default=Default%20Message'),
             String
         )
 
         then: "default message is rendered"
         response.status.code == 200
         response.body().contains('Default Message')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:formatDate ==========
 
     def "g:formatDate tag formats date"() {
-        given: "a request with date"
-        def client = createClient()
-
         when: "calling the built-in formatDate test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInFormatDate"),
+            HttpRequest.GET('/tagLibTest/testBuiltInFormatDate'),
             String
         )
 
@@ -863,20 +645,14 @@ class TagLibSpec extends Specification {
         response.status.code == 200
         // Just verify it rendered something in date format
         response.body() =~ /\d{4}-\d{2}-\d{2}/
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:formatNumber ==========
 
     def "g:formatNumber tag formats number"() {
-        given: "a request with number"
-        def client = createClient()
-
         when: "calling the built-in formatNumber test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInFormatNumber?number=1234567.89"),
+            HttpRequest.GET('/tagLibTest/testBuiltInFormatNumber?number=1234567.89'),
             String
         )
 
@@ -884,20 +660,14 @@ class TagLibSpec extends Specification {
         response.status.code == 200
         // Should contain formatted number (locale-dependent)
         response.body() =~ /1.*234.*567/
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:set ==========
 
     def "g:set tag sets and updates variables"() {
-        given: "a request to test variable setting"
-        def client = createClient()
-
         when: "calling the built-in set test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInSet?initialValue=First&newValue=Second"),
+            HttpRequest.GET('/tagLibTest/testBuiltInSet?initialValue=First&newValue=Second'),
             String
         )
 
@@ -906,80 +676,56 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('id="set-initial">First')
         body.contains('id="set-updated">Second')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:join ==========
 
     def "g:join tag joins items with delimiter"() {
-        given: "a request with items"
-        def client = createClient()
-
         when: "calling the built-in join test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInJoin?items=red,green,blue&delimiter=%20-%20"),
+            HttpRequest.GET('/tagLibTest/testBuiltInJoin?items=red,green,blue&delimiter=%20-%20'),
             String
         )
 
         then: "items are joined"
         response.status.code == 200
         response.body().contains('red - green - blue')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:include ==========
 
     def "g:include tag includes content from another action"() {
-        given: "a request to test include"
-        def client = createClient()
-
         when: "calling the built-in include test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInInclude?message=Test%20Message"),
+            HttpRequest.GET('/tagLibTest/testBuiltInInclude?message=Test%20Message'),
             String
         )
 
         then: "included content is rendered"
         response.status.code == 200
         response.body().contains('Included content: Test Message')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:render ==========
 
     def "g:render tag renders template with model"() {
-        given: "a request to test template rendering"
-        def client = createClient()
-
         when: "calling the built-in render test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInRender?text=Hello%20Template"),
+            HttpRequest.GET('/tagLibTest/testBuiltInRender?text=Hello%20Template'),
             String
         )
 
         then: "template is rendered"
         response.status.code == 200
         response.body().contains('Template content: Hello Template')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:while ==========
 
     def "g:while tag loops while condition is true"() {
-        given: "a request with count"
-        def client = createClient()
-
         when: "calling the built-in while test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInWhile?count=3"),
+            HttpRequest.GET('/tagLibTest/testBuiltInWhile?count=3'),
             String
         )
 
@@ -990,20 +736,14 @@ class TagLibSpec extends Specification {
         body.contains('Count: 2')
         body.contains('Count: 3')
         !body.contains('Count: 4')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:uploadForm ==========
 
     def "g:uploadForm tag creates multipart form"() {
-        given: "a request to create upload form"
-        def client = createClient()
-
         when: "calling the built-in uploadForm test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInUploadForm"),
+            HttpRequest.GET('/tagLibTest/testBuiltInUploadForm'),
             String
         )
 
@@ -1012,20 +752,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('<form')
         body.contains('enctype="multipart/form-data"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:select ==========
 
     def "g:select tag creates select element with options"() {
-        given: "a request to create select"
-        def client = createClient()
-
         when: "calling the built-in select test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInSelect?selected=2"),
+            HttpRequest.GET('/tagLibTest/testBuiltInSelect?selected=2'),
             String
         )
 
@@ -1035,20 +769,14 @@ class TagLibSpec extends Specification {
         body.contains('<select')
         body.contains('<option')
         body.contains('value="2" selected')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:radio ==========
 
     def "g:radio tag creates radio buttons"() {
-        given: "a request to create radio buttons"
-        def client = createClient()
-
         when: "calling the built-in radio test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInRadio?selected=Option%20B"),
+            HttpRequest.GET('/tagLibTest/testBuiltInRadio?selected=Option%20B'),
             String
         )
 
@@ -1057,20 +785,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('type="radio"')
         body.contains('checked="checked"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:checkBox ==========
 
     def "g:checkBox tag creates checkbox"() {
-        given: "a request to create checkbox"
-        def client = createClient()
-
         when: "calling the built-in checkbox test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInCheckBox?checked=true"),
+            HttpRequest.GET('/tagLibTest/testBuiltInCheckBox?checked=true'),
             String
         )
 
@@ -1079,20 +801,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('type="checkbox"')
         body.contains('checked="checked"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:textArea ==========
 
     def "g:textArea tag creates textarea"() {
-        given: "a request to create textarea"
-        def client = createClient()
-
         when: "calling the built-in textarea test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInTextArea?value=Test%20Content&rows=5&cols=40"),
+            HttpRequest.GET('/tagLibTest/testBuiltInTextArea?value=Test%20Content&rows=5&cols=40'),
             String
         )
 
@@ -1103,20 +819,14 @@ class TagLibSpec extends Specification {
         body.contains('rows="5"')
         body.contains('cols="40"')
         body.contains('Test Content')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:textField ==========
 
     def "g:textField tag creates text input"() {
-        given: "a request to create text field"
-        def client = createClient()
-
         when: "calling the built-in textField test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInTextField?value=Test%20Value&maxlength=50"),
+            HttpRequest.GET('/tagLibTest/testBuiltInTextField?value=Test%20Value&maxlength=50'),
             String
         )
 
@@ -1126,40 +836,28 @@ class TagLibSpec extends Specification {
         body.contains('type="text"')
         body.contains('value="Test Value"')
         body.contains('maxlength="50"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:passwordField ==========
 
     def "g:passwordField tag creates password input"() {
-        given: "a request to create password field"
-        def client = createClient()
-
         when: "calling the built-in passwordField test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInPasswordField"),
+            HttpRequest.GET('/tagLibTest/testBuiltInPasswordField'),
             String
         )
 
         then: "password field is rendered"
         response.status.code == 200
         response.body().contains('type="password"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:hiddenField ==========
 
     def "g:hiddenField tag creates hidden input"() {
-        given: "a request to create hidden field"
-        def client = createClient()
-
         when: "calling the built-in hiddenField test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInHiddenField?value=secret-value"),
+            HttpRequest.GET('/tagLibTest/testBuiltInHiddenField?value=secret-value'),
             String
         )
 
@@ -1168,40 +866,28 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('type="hidden"')
         body.contains('value="secret-value"')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:fieldValue ==========
 
     def "g:fieldValue tag extracts bean field value"() {
-        given: "a request with a bean"
-        def client = createClient()
-
         when: "calling the built-in fieldValue test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInFieldValue?field=title"),
+            HttpRequest.GET('/tagLibTest/testBuiltInFieldValue?field=title'),
             String
         )
 
         then: "field value is extracted"
         response.status.code == 200
         response.body().contains('Grails in Action')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:sortableColumn ==========
 
     def "g:sortableColumn tag creates sortable table header"() {
-        given: "a request to create sortable columns"
-        def client = createClient()
-
         when: "calling the built-in sortableColumn test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInSortableColumn"),
+            HttpRequest.GET('/tagLibTest/testBuiltInSortableColumn'),
             String
         )
 
@@ -1211,20 +897,14 @@ class TagLibSpec extends Specification {
         body.contains('<th')
         body.contains('Title')
         body.contains('Author')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Built-in Tag: g:paginate ==========
 
     def "g:paginate tag creates pagination links"() {
-        given: "a request for pagination"
-        def client = createClient()
-
         when: "calling the built-in paginate test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testBuiltInPaginate?total=100&max=10&offset=0"),
+            HttpRequest.GET('/tagLibTest/testBuiltInPaginate?total=100&max=10&offset=0'),
             String
         )
 
@@ -1233,20 +913,14 @@ class TagLibSpec extends Specification {
         def body = response.body()
         // Pagination should contain some links
         body.contains('class=')
-
-        cleanup:
-        client.close()
     }
 
     // ========== Complex/Combined Tests ==========
 
     def "nested custom tags render correctly"() {
-        given: "a request for nested tags"
-        def client = createClient()
-
         when: "calling the nested tags test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testNestedTags"),
+            HttpRequest.GET('/tagLibTest/testNestedTags'),
             String
         )
 
@@ -1255,18 +929,12 @@ class TagLibSpec extends Specification {
         def body = response.body()
         body.contains('<ul>')
         body.contains('class="badge')
-
-        cleanup:
-        client.close()
     }
 
     def "tags work with complex model data"() {
-        given: "a request with complex model"
-        def client = createClient()
-
         when: "calling the tags with model test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testTagsWithModel"),
+            HttpRequest.GET('/tagLibTest/testTagsWithModel'),
             String
         )
 
@@ -1280,18 +948,12 @@ class TagLibSpec extends Specification {
         body.contains('Charlie')
         body.contains('Admin')
         body.contains('User')
-
-        cleanup:
-        client.close()
     }
 
     def "encoding tags properly escape content"() {
-        given: "a request with content to encode"
-        def client = createClient()
-
         when: "calling the encoding tags test endpoint"
         def response = client.toBlocking().exchange(
-            HttpRequest.GET("/tagLibTest/testEncodingTags"),
+            HttpRequest.GET('/tagLibTest/testEncodingTags'),
             String
         )
 
@@ -1302,8 +964,5 @@ class TagLibSpec extends Specification {
         body.contains('&lt;script&gt;')
         // Raw content should preserve HTML
         body.contains('id="raw-content">')
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/urlmappings/UrlMappingsSpec.groovy b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/urlmappings/UrlMappingsSpec.groovy
index 894214b069..c1e7603912 100644
--- a/grails-test-examples/app1/src/integration-test/groovy/functionaltests/urlmappings/UrlMappingsSpec.groovy
+++ b/grails-test-examples/app1/src/integration-test/groovy/functionaltests/urlmappings/UrlMappingsSpec.groovy
@@ -16,46 +16,49 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package functionaltests.urlmappings
 
-import functionaltests.Application
-import grails.testing.mixin.integration.Integration
 import groovy.json.JsonSlurper
-import io.micronaut.http.HttpMethod
+
 import io.micronaut.http.HttpRequest
-import io.micronaut.http.HttpResponse
 import io.micronaut.http.HttpStatus
 import io.micronaut.http.client.HttpClient
 import io.micronaut.http.client.exceptions.HttpClientResponseException
 import spock.lang.Narrative
+import spock.lang.Shared
 import spock.lang.Specification
 
+import grails.testing.mixin.integration.Integration
+
 /**
  * Integration tests for Grails URL mappings features.
  * 
  * Tests static paths, path variables, constraints, HTTP method mappings,
  * redirects, and various URL mapping patterns.
  */
-@Integration(applicationClass = Application)
+@Integration
 @Narrative('''
 Grails URL mappings provide flexible routing of HTTP requests to controller actions.
 This includes path variables, constraints, HTTP method-based routing, and redirects.
 ''')
 class UrlMappingsSpec extends Specification {
 
-    private HttpClient createClient() {
-        HttpClient.create(new URL("http://localhost:$serverPort"))
+    @Shared
+    HttpClient client
+
+    def setup() {
+        client = client ?: HttpClient.create(new URL("http://localhost:$serverPort"))
+    }
+
+    def cleanupSpec() {
+        client.close()
     }
 
     // ========== Static Path Mappings ==========
 
     def "static path mapping routes to correct action"() {
-        given:
-        def client = createClient()
-
         when: "accessing static path"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/test'),
             String
         )
@@ -65,19 +68,13 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.controller == 'urlMappingsTest'
         json.action == 'index'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Path Variable Mappings ==========
 
     def "single path variable is captured"() {
-        given:
-        def client = createClient()
-
         when: "accessing path with variable"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/items/123'),
             String
         )
@@ -87,17 +84,11 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'show'
         json.id == '123'
-
-        cleanup:
-        client.close()
     }
 
     def "path variable accepts alphanumeric values"() {
-        given:
-        def client = createClient()
-
         when: "accessing path with alphanumeric id"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/items/abc-123'),
             String
         )
@@ -106,17 +97,11 @@ class UrlMappingsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.id == 'abc-123'
-
-        cleanup:
-        client.close()
     }
 
     def "multiple path variables are captured"() {
-        given:
-        def client = createClient()
-
         when: "accessing path with multiple variables"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/archive/2024/03/15'),
             String
         )
@@ -128,19 +113,13 @@ class UrlMappingsSpec extends Specification {
         json.year == '2024'
         json.month == '03'
         json.day == '15'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Named URL Mappings ==========
 
     def "named mapping routes correctly"() {
-        given:
-        def client = createClient()
-
         when: "accessing named mapping"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/named/test-name'),
             String
         )
@@ -150,19 +129,13 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'named'
         json.name == 'test-name'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Constrained Path Variables ==========
 
     def "constrained path accepts valid values"() {
-        given:
-        def client = createClient()
-
         when: "accessing with valid constrained value"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/codes/ABC'),
             String
         )
@@ -172,15 +145,9 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'constrained'
         json.code == 'ABC'
-
-        cleanup:
-        client.close()
     }
 
     def "constrained path rejects invalid values"() {
-        given:
-        def client = createClient()
-
         when: "accessing with invalid constrained value (lowercase)"
         client.toBlocking().exchange(
             HttpRequest.GET('/api/codes/abc'),
@@ -188,17 +155,11 @@ class UrlMappingsSpec extends Specification {
         )
 
         then: "request is rejected with 404"
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.NOT_FOUND
-
-        cleanup:
-        client.close()
     }
 
     def "constrained path rejects numeric values"() {
-        given:
-        def client = createClient()
-
         when: "accessing with numeric value"
         client.toBlocking().exchange(
             HttpRequest.GET('/api/codes/123'),
@@ -206,21 +167,15 @@ class UrlMappingsSpec extends Specification {
         )
 
         then: "request is rejected with 404"
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.NOT_FOUND
-
-        cleanup:
-        client.close()
     }
 
     // ========== HTTP Method Mappings ==========
 
     def "GET request routes to list action"() {
-        given:
-        def client = createClient()
-
         when: "making GET request to resources"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/resources'),
             String
         )
@@ -229,17 +184,11 @@ class UrlMappingsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'list'
-
-        cleanup:
-        client.close()
     }
 
     def "POST request routes to save action"() {
-        given:
-        def client = createClient()
-
         when: "making POST request to resources"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.POST('/api/resources', '{}'),
             String
         )
@@ -249,17 +198,11 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'save'
         json.method == 'POST'
-
-        cleanup:
-        client.close()
     }
 
     def "PUT request routes to update action"() {
-        given:
-        def client = createClient()
-
         when: "making PUT request to resources with id"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.PUT('/api/resources/42', '{}'),
             String
         )
@@ -270,17 +213,11 @@ class UrlMappingsSpec extends Specification {
         json.action == 'update'
         json.id == '42'
         json.method == 'PUT'
-
-        cleanup:
-        client.close()
     }
 
     def "DELETE request routes to delete action"() {
-        given:
-        def client = createClient()
-
         when: "making DELETE request to resources with id"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.DELETE('/api/resources/42'),
             String
         )
@@ -291,19 +228,13 @@ class UrlMappingsSpec extends Specification {
         json.action == 'delete'
         json.id == '42'
         json.method == 'DELETE'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Optional Path Variables ==========
 
     def "optional path variable with value"() {
-        given:
-        def client = createClient()
-
         when: "accessing with optional variable provided"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/optional/required-value/optional-value'),
             String
         )
@@ -313,17 +244,11 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.required == 'required-value'
         json.optional == 'optional-value'
-
-        cleanup:
-        client.close()
     }
 
     def "optional path variable without value uses default"() {
-        given:
-        def client = createClient()
-
         when: "accessing without optional variable"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/optional/required-value'),
             String
         )
@@ -333,19 +258,13 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.required == 'required-value'
         json.optional == 'default'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Redirect Mappings ==========
 
     def "redirect mapping performs redirect"() {
-        given:
-        def client = HttpClient.create(new URL("http://localhost:$serverPort"))
-
         when: "accessing redirect mapping"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/old-endpoint').header('Accept', '*/*'),
             String
         )
@@ -354,19 +273,13 @@ class UrlMappingsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'index'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Default Controller/Action Mapping ==========
 
     def "default mapping with controller and action"() {
-        given:
-        def client = createClient()
-
         when: "using default mapping pattern"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/urlMappingsTest/show/99'),
             String
         )
@@ -377,17 +290,11 @@ class UrlMappingsSpec extends Specification {
         json.controller == 'urlMappingsTest'
         json.action == 'show'
         json.id == '99'
-
-        cleanup:
-        client.close()
     }
 
     def "default mapping with format extension"() {
-        given:
-        def client = createClient()
-
         when: "using default mapping with format"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/urlMappingsTest/list.json'),
             String
         )
@@ -396,19 +303,13 @@ class UrlMappingsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.action == 'list'
-
-        cleanup:
-        client.close()
     }
 
     // ========== Query Parameter Handling ==========
 
     def "query parameters are accessible in action"() {
-        given:
-        def client = createClient()
-
         when: "accessing with query parameters"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/test?param1=value1&param2=value2'),
             String
         )
@@ -418,19 +319,13 @@ class UrlMappingsSpec extends Specification {
         def json = new JsonSlurper().parseText(response.body())
         json.params.param1 == 'value1'
         json.params.param2 == 'value2'
-
-        cleanup:
-        client.close()
     }
 
     // ========== HTTP Method Detection ==========
 
     def "request method is correctly detected"() {
-        given:
-        def client = createClient()
-
         when: "making request"
-        HttpResponse<String> response = client.toBlocking().exchange(
+        def response = client.toBlocking().exchange(
             HttpRequest.GET('/api/method-test'),
             String
         )
@@ -439,17 +334,11 @@ class UrlMappingsSpec extends Specification {
         response.status == HttpStatus.OK
         def json = new JsonSlurper().parseText(response.body())
         json.method == 'GET'
-
-        cleanup:
-        client.close()
     }
 
     // ========== 404 Not Found ==========
 
     def "non-existent path returns 404"() {
-        given:
-        def client = createClient()
-
         when: "accessing non-existent path"
         client.toBlocking().exchange(
             HttpRequest.GET('/api/does-not-exist'),
@@ -457,10 +346,7 @@ class UrlMappingsSpec extends Specification {
         )
 
         then: "returns 404"
-        HttpClientResponseException e = thrown()
+        def e = thrown(HttpClientResponseException)
         e.status == HttpStatus.NOT_FOUND
-
-        cleanup:
-        client.close()
     }
 }
diff --git a/grails-test-examples/async-events-pubsub-demo/grails-app/services/pubsub/demo/TotalService.groovy b/grails-test-examples/async-events-pubsub-demo/grails-app/services/pubsub/demo/TotalService.groovy
index 350af8c4c4..c3e14020dc 100644
--- a/grails-test-examples/async-events-pubsub-demo/grails-app/services/pubsub/demo/TotalService.groovy
+++ b/grails-test-examples/async-events-pubsub-demo/grails-app/services/pubsub/demo/TotalService.groovy
@@ -16,14 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package pubsub.demo
 
-import grails.events.Event
-import grails.events.annotation.Subscriber
+import java.util.concurrent.atomic.AtomicInteger
+
 import groovy.transform.CompileStatic
 
-import java.util.concurrent.atomic.AtomicInteger
+import grails.events.Event
+import grails.events.annotation.Subscriber
 
 @CompileStatic
 class TotalService {
diff --git a/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/AsyncEventsSpec.groovy b/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/AsyncEventsSpec.groovy
index 6beef73208..9b7966c00a 100644
--- a/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/AsyncEventsSpec.groovy
+++ b/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/AsyncEventsSpec.groovy
@@ -16,15 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package pubsub.demo
 
-import grails.gorm.transactions.Rollback
-import grails.testing.mixin.integration.Integration
 import jakarta.inject.Inject
+
 import spock.lang.Specification
 import spock.util.concurrent.PollingConditions
 
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
+
 /**
  * Additional integration tests for async events functionality.
  * 
@@ -50,7 +51,7 @@ class AsyncEventsSpec extends Specification {
         totalService.reset()
         bookSubscriber.reset()
         // Small delay to let any in-flight events complete
-        Thread.sleep(100)
+        sleep(100)
     }
 
     void "multiple sum events accumulate correctly"() {
@@ -105,12 +106,9 @@ class AsyncEventsSpec extends Specification {
         def book3 = bookService.saveBook('Book Three')
 
         then: "all books are saved"
-        book1 != null
-        book2 != null
-        book3 != null
-        book1.id != null
-        book2.id != null
-        book3.id != null
+        book1?.id != null
+        book2?.id != null
+        book3?.id != null
     }
 
     void "book events are received after save"() {
diff --git a/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/PubSubSpec.groovy b/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/PubSubSpec.groovy
index abc91ab7cd..4e153641a2 100644
--- a/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/PubSubSpec.groovy
+++ b/grails-test-examples/async-events-pubsub-demo/src/integration-test/groovy/pubsub/demo/PubSubSpec.groovy
@@ -16,15 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package pubsub.demo
 
-import grails.gorm.transactions.Rollback
-import grails.testing.mixin.integration.Integration
 import jakarta.inject.Inject
+
 import spock.lang.Specification
 import spock.util.concurrent.PollingConditions
 
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
+
 /**
  * Created by graemerocher on 03/04/2017.
  */
@@ -42,7 +43,7 @@ class PubSubSpec extends Specification {
         totalService.reset()
         bookSubscriber.reset()
         // Small delay to let any in-flight events from other tests complete
-        Thread.sleep(100)
+        sleep(100)
     }
 
     void 'Test event bus within Grails'() {
diff --git a/grails-test-examples/async-events-pubsub-demo/src/main/groovy/pubsub/demo/BookSubscriber.groovy b/grails-test-examples/async-events-pubsub-demo/src/main/groovy/pubsub/demo/BookSubscriber.groovy
index 8b8e5c58b7..ed70582941 100644
--- a/grails-test-examples/async-events-pubsub-demo/src/main/groovy/pubsub/demo/BookSubscriber.groovy
+++ b/grails-test-examples/async-events-pubsub-demo/src/main/groovy/pubsub/demo/BookSubscriber.groovy
@@ -16,15 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package pubsub.demo
 
-import grails.events.annotation.Subscriber
+import java.util.concurrent.ConcurrentLinkedDeque
+
 import groovy.transform.CompileStatic
-import org.grails.datastore.mapping.engine.event.PreInsertEvent
+
 import org.springframework.stereotype.Component
 
-import java.util.concurrent.ConcurrentLinkedDeque
+import grails.events.annotation.Subscriber
+import org.grails.datastore.mapping.engine.event.PreInsertEvent
 
 @Component
 @CompileStatic
diff --git a/grails-test-examples/gorm/grails-app/domain/gorm/Book.groovy b/grails-test-examples/gorm/grails-app/domain/gorm/Book.groovy
index 7546fd2326..9ee5f18bde 100644
--- a/grails-test-examples/gorm/grails-app/domain/gorm/Book.groovy
+++ b/grails-test-examples/gorm/grails-app/domain/gorm/Book.groovy
@@ -27,8 +27,6 @@ import static grails.gorm.hibernate.mapping.MappingBuilder.*
  */
 class Book {
 
-    def testService
-
     String title
     String isbn
     String description
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/FieldsValidationSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/FieldsValidationSpec.groovy
index 07d1df3cb6..d389dae685 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/FieldsValidationSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/FieldsValidationSpec.groovy
@@ -16,13 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
+import gorm.pages.AuthorCreatePage
+import gorm.pages.BookCreatePage
+import spock.lang.Stepwise
+
 import grails.plugin.geb.ContainerGebSpec
 import grails.testing.mixin.integration.Integration
-import gorm.pages.*
-import spock.lang.Stepwise
 
 /**
  * Functional tests for fields plugin validation error display in gorm test app.
@@ -30,18 +31,19 @@ import spock.lang.Stepwise
  * Tests that validation errors are rendered correctly by the fields plugin
  * in scaffolded views.
  */
-@Integration
 @Stepwise
+@Integration
 class FieldsValidationSpec extends ContainerGebSpec {
 
+    // TODO: Not fully implemented
     def "author email validation shows error for invalid format"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "entering invalid email"
-        name = 'Test Author'
-        email = 'not-an-email'
-        createButton.click()
+        page.name = 'Test Author'
+        page.email = 'not-an-email'
+        page.createButton.click()
 
         then: "validation error is displayed"
         waitFor {
@@ -55,14 +57,15 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "author name blank validation shows error"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "submitting with blank name"
-        name = ''
-        email = 'valid@example.com'
-        createButton.click()
+        page.name = ''
+        page.email = 'valid@example.com'
+        page.createButton.click()
 
         then: "validation error is displayed for name"
         waitFor {
@@ -73,21 +76,22 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "author unique email constraint shows error"() {
         given: "create an author with email"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
         // Use a unique email with timestamp to avoid conflicts with other tests
         def uniqueEmail = "unique.test.${System.currentTimeMillis()}@example.com"
-        name = 'First Author'
-        email = uniqueEmail
-        createButton.click()
+        page.name = 'First Author'
+        page.email = uniqueEmail
+        page.createButton.click()
         waitFor(10) { currentUrl.contains('/author/show/') || currentUrl.contains('/author/index') }
 
         when: "trying to create another author with same email"
-        to AuthorCreatePage
-        name = 'Second Author'
-        email = uniqueEmail
-        createButton.click()
+        page = to AuthorCreatePage
+        page.name = 'Second Author'
+        page.email = uniqueEmail
+        page.createButton.click()
 
         then: "unique constraint error is displayed - we should stay on create/save page or see errors"
         waitFor(10) {
@@ -105,13 +109,14 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "book title blank validation shows error"() {
         when: "navigating to create book page"
-        to BookCreatePage
+        def page = to BookCreatePage
 
         and: "submitting with blank title"
-        titleField.value('')
-        createButton.click()
+        page.titleField.value('')
+        page.createButton.click()
 
         then: "validation error is displayed"
         waitFor {
@@ -123,16 +128,17 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "book pageCount min validation shows error"() {
         when: "navigating to create book page"
-        to BookCreatePage
+        def page = to BookCreatePage
 
         and: "entering invalid page count"
-        titleField.value('Valid Title')
-        if (pageCount.displayed) {
-            pageCount.value('0')  // min is 1
+        page.titleField.value('Valid Title')
+        if (page.pageCount.displayed) {
+            page.pageCount.value('0')  // min is 1
         }
-        createButton.click()
+        page.createButton.click()
 
         then: "validation error is displayed or book is created (if pageCount nullable)"
         waitFor {
@@ -145,16 +151,17 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "book isbn pattern validation shows error for invalid format"() {
         when: "navigating to create book page"
-        to BookCreatePage
+        def page = to BookCreatePage
 
         and: "entering invalid ISBN"
-        titleField.value('Book With Invalid ISBN')
-        if (isbn.displayed) {
-            isbn.value('invalid-isbn')  // Should match /^(?:\d{10}|\d{13})$/
+        page.titleField.value('Book With Invalid ISBN')
+        if (page.isbn.displayed) {
+            page.isbn.value('invalid-isbn')  // Should match /^(?:\d{10}|\d{13})$/
         }
-        createButton.click()
+        page.createButton.click()
 
         then: "validation error is displayed or book created (isbn nullable)"
         waitFor {
@@ -169,29 +176,29 @@ class FieldsValidationSpec extends ContainerGebSpec {
 
     def "validation errors persist field values on re-display"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "filling in some fields and triggering validation error"
-        name = 'Preserved Name'
-        email = 'invalid-email'
-        createButton.click()
+        page.name = 'Preserved Name'
+        page.email = 'invalid-email'
+        page.createButton.click()
 
         then: "name field value is preserved"
         waitFor { currentUrl.contains('/author/create') || $('input[name=name]').value() }
         
         // The field should retain its value after validation failure
-        $('input[name=name]').value() == 'Preserved Name' ||
-        $('input[name=name]').value()?.contains('Preserved')
+        $('input[name=name]').value() == 'Preserved Name'
     }
 
+    // TODO: Not fully implemented
     def "multiple validation errors displayed together"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "submitting with multiple invalid fields"
-        name = ''
-        email = 'not-valid'
-        createButton.click()
+        page.name = ''
+        page.email = 'not-valid'
+        page.createButton.click()
 
         then: "multiple errors should be displayed"
         waitFor {
@@ -202,16 +209,17 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "form retains field values after validation error"() {
         when: "navigating to create book page"
-        to BookCreatePage
+        def page = to BookCreatePage
 
         and: "filling form with some valid and invalid data"
-        titleField.value('')  // Invalid - blank
-        if (description.displayed) {
-            description.value('This is a test description that should be preserved')
+        page.titleField.value('')  // Invalid - blank
+        if (page.description.displayed) {
+            page.description.value('This is a test description that should be preserved')
         }
-        createButton.click()
+        page.createButton.click()
 
         then: "form is re-displayed with preserved values"
         waitFor { currentUrl.contains('/book/create') || currentUrl.contains('/book/save') }
@@ -224,14 +232,15 @@ class FieldsValidationSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "error styling applied to invalid fields"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "triggering validation error"
-        name.value('')
-        email.value('valid@example.com')
-        createButton.click()
+        page.name.value('')
+        page.email.value('valid@example.com')
+        page.createButton.click()
 
         then: "we stay on create/save page (validation failed) or error styling is applied"
         waitFor { 
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCascadeOperationsSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCascadeOperationsSpec.groovy
index baf5054763..931db50d6e 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCascadeOperationsSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCascadeOperationsSpec.groovy
@@ -16,12 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
+import spock.lang.Specification
+
 import grails.gorm.transactions.Rollback
 import grails.testing.mixin.integration.Integration
-import spock.lang.Specification
 
 /**
  * Tests for GORM Cascade Operations.
@@ -35,16 +35,16 @@ import spock.lang.Specification
  * - Orphan removal
  * - Bidirectional associations
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class GormCascadeOperationsSpec extends Specification {
 
     def setup() {
         // Clean up test data
-        Book.executeUpdate("delete from Book")
-        Author.executeUpdate("delete from Author")
-        User.executeUpdate("delete from User")
-        City.executeUpdate("delete from City")
+        Book.executeUpdate('delete from Book')
+        Author.executeUpdate('delete from Author')
+        User.executeUpdate('delete from User')
+        City.executeUpdate('delete from City')
     }
 
     // ============================================
@@ -53,9 +53,9 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test saving parent cascades to children with addTo"() {
         given: "an author with books added via addTo"
-        def author = new Author(name: "George Orwell", email: "george@orwell.com")
-        author.addToBooks(new Book(title: "1984", pageCount: 328, inStock: true))
-        author.addToBooks(new Book(title: "Animal Farm", pageCount: 112, inStock: true))
+        def author = new Author(name: 'George Orwell', email: 'george@orwell.com')
+        author.addToBooks(new Book(title: '1984', pageCount: 328, inStock: true))
+        author.addToBooks(new Book(title: 'Animal Farm', pageCount: 112, inStock: true))
 
         when: "saving only the author"
         author.save(flush: true)
@@ -63,17 +63,17 @@ class GormCascadeOperationsSpec extends Specification {
         then: "books are also saved (cascade)"
         Author.count() == 1
         Book.count() == 2
-        Book.findByTitle("1984").author == author
-        Book.findByTitle("Animal Farm").author == author
+        Book.findByTitle('1984').author == author
+        Book.findByTitle('Animal Farm').author == author
     }
 
     void "test saving child with belongsTo saves parent reference"() {
         given: "an author"
-        def author = new Author(name: "J.K. Rowling", email: "jk@rowling.com")
+        def author = new Author(name: 'J.K. Rowling', email: 'jk@rowling.com')
         author.save(flush: true)
 
         when: "creating a book with the author using addToBooks"
-        def book = new Book(title: "Harry Potter", pageCount: 309, inStock: true)
+        def book = new Book(title: 'Harry Potter', pageCount: 309, inStock: true)
         author.addToBooks(book)
         author.save(flush: true)
 
@@ -84,9 +84,9 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test cascade save with nested new objects"() {
         given: "a new author with new books - all unsaved"
-        def author = new Author(name: "Brandon Sanderson", email: "brandon@sanderson.com")
-        def book1 = new Book(title: "Mistborn", pageCount: 541, inStock: true)
-        def book2 = new Book(title: "The Way of Kings", pageCount: 1007, inStock: true)
+        def author = new Author(name: 'Brandon Sanderson', email: 'brandon@sanderson.com')
+        def book1 = new Book(title: 'Mistborn', pageCount: 541, inStock: true)
+        def book2 = new Book(title: 'The Way of Kings', pageCount: 1007, inStock: true)
 
         author.addToBooks(book1)
         author.addToBooks(book2)
@@ -106,39 +106,39 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test updating parent does not affect children unless changed"() {
         given: "an author with books"
-        def author = new Author(name: "Original Name", email: "original@email.com")
-        author.addToBooks(new Book(title: "Book1", pageCount: 100, inStock: true))
+        def author = new Author(name: 'Original Name', email: 'original@email.com')
+        author.addToBooks(new Book(title: 'Book1', pageCount: 100, inStock: true))
         author.save(flush: true)
 
         def bookId = author.books[0].id
 
         when: "updating only the author"
-        author.name = "Updated Name"
+        author.name = 'Updated Name'
         author.save(flush: true)
 
         then: "book remains unchanged"
         def book = Book.get(bookId)
-        book.title == "Book1"
+        book.title == 'Book1'
     }
 
     void "test dirty checking with associations"() {
         given: "an author with books"
-        def author = new Author(name: "Test Author", email: "test@author.com")
-        author.addToBooks(new Book(title: "Test Book", pageCount: 200, inStock: true))
+        def author = new Author(name: 'Test Author', email: 'test@author.com')
+        author.addToBooks(new Book(title: 'Test Book', pageCount: 200, inStock: true))
         author.save(flush: true)
 
         when: "modifying a book through the author"
         def book = author.books.first()
-        book.title = "Modified Title"
+        book.title = 'Modified Title'
         author.save(flush: true)
 
         // Clear session and reload
         Author.withSession { it.flush(); it.clear() }
-        def reloaded = Book.findByTitle("Modified Title")
+        def reloaded = Book.findByTitle('Modified Title')
 
         then: "book changes are persisted"
         reloaded != null
-        reloaded.title == "Modified Title"
+        reloaded.title == 'Modified Title'
     }
 
     // ============================================
@@ -147,28 +147,28 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test deleting child does not delete parent"() {
         given: "an author with multiple books"
-        def author = new Author(name: "Multi Book Author", email: "multi@author.com")
-        author.addToBooks(new Book(title: "Keep Me", pageCount: 100, inStock: true))
-        author.addToBooks(new Book(title: "Delete Me", pageCount: 100, inStock: true))
+        def author = new Author(name: 'Multi Book Author', email: 'multi@author.com')
+        author.addToBooks(new Book(title: 'Keep Me', pageCount: 100, inStock: true))
+        author.addToBooks(new Book(title: 'Delete Me', pageCount: 100, inStock: true))
         author.save(flush: true)
 
         def authorId = author.id
 
         when: "deleting one book"
-        def bookToDelete = Book.findByTitle("Delete Me")
+        def bookToDelete = Book.findByTitle('Delete Me')
         author.removeFromBooks(bookToDelete)
         bookToDelete.delete(flush: true)
 
         then: "author still exists with remaining book"
         Author.get(authorId) != null
         Author.get(authorId).books.size() == 1
-        Book.findByTitle("Keep Me") != null
+        Book.findByTitle('Keep Me') != null
     }
 
     void "test belongsTo allows orphan removal"() {
         given: "an author with a book"
-        def author = new Author(name: "Orphan Test", email: "orphan@test.com")
-        def book = new Book(title: "Orphan Book", pageCount: 100, inStock: true)
+        def author = new Author(name: 'Orphan Test', email: 'orphan@test.com')
+        def book = new Book(title: 'Orphan Book', pageCount: 100, inStock: true)
         author.addToBooks(book)
         author.save(flush: true)
 
@@ -190,9 +190,9 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test hasMany cascade save for City and Users"() {
         given: "a city with users"
-        def city = new City(name: "London")
-        city.addToUsers(new User(name: "Alice"))
-        city.addToUsers(new User(name: "Bob"))
+        def city = new City(name: 'London')
+        city.addToUsers(new User(name: 'Alice'))
+        city.addToUsers(new User(name: 'Bob'))
 
         when: "saving the city"
         city.save(flush: true)
@@ -200,24 +200,24 @@ class GormCascadeOperationsSpec extends Specification {
         then: "users are also saved"
         City.count() == 1
         User.count() == 2
-        User.findByName("Alice").city == city
+        User.findByName('Alice').city == city
     }
 
     void "test removing user from city"() {
         given: "a city with users"
-        def city = new City(name: "Paris")
-        city.addToUsers(new User(name: "Jean"))
-        city.addToUsers(new User(name: "Pierre"))
+        def city = new City(name: 'Paris')
+        city.addToUsers(new User(name: 'Jean'))
+        city.addToUsers(new User(name: 'Pierre'))
         city.save(flush: true)
 
         when: "removing one user"
-        def jean = User.findByName("Jean")
+        def jean = User.findByName('Jean')
         city.removeFromUsers(jean)
         jean.delete(flush: true)
 
         then: "user is removed"
         city.users.size() == 1
-        User.findByName("Jean") == null
+        User.findByName('Jean') == null
     }
 
     // ============================================
@@ -226,9 +226,9 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test bidirectional navigation"() {
         given: "an author with books"
-        def author = new Author(name: "Nav Author", email: "nav@author.com")
-        def book1 = new Book(title: "Nav Book 1", pageCount: 100, inStock: true)
-        def book2 = new Book(title: "Nav Book 2", pageCount: 100, inStock: true)
+        def author = new Author(name: 'Nav Author', email: 'nav@author.com')
+        def book1 = new Book(title: 'Nav Book 1', pageCount: 100, inStock: true)
+        def book2 = new Book(title: 'Nav Book 2', pageCount: 100, inStock: true)
         author.addToBooks(book1)
         author.addToBooks(book2)
         author.save(flush: true)
@@ -246,9 +246,9 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test lazy loading of associations"() {
         given: "a city with users"
-        def city = new City(name: "Berlin")
-        city.addToUsers(new User(name: "Hans"))
-        city.addToUsers(new User(name: "Klaus"))
+        def city = new City(name: 'Berlin')
+        city.addToUsers(new User(name: 'Hans'))
+        city.addToUsers(new User(name: 'Klaus'))
         city.save(flush: true)
         def cityId = city.id
 
@@ -260,7 +260,7 @@ class GormCascadeOperationsSpec extends Specification {
 
         then: "city is loaded"
         loadedCity != null
-        loadedCity.name == "Berlin"
+        loadedCity.name == 'Berlin'
 
         and: "users can be lazily loaded"
         loadedCity.users.size() == 2
@@ -286,7 +286,7 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test updating multiple children"() {
         given: "an author with multiple books"
-        def author = new Author(name: "Batch Author", email: "batch@author.com")
+        def author = new Author(name: 'Batch Author', email: 'batch@author.com')
         5.times { i ->
             author.addToBooks(new Book(title: "Book ${i}", pageCount: 100 + i, inStock: true))
         }
@@ -300,7 +300,7 @@ class GormCascadeOperationsSpec extends Specification {
 
         // Clear and reload
         Author.withSession { it.flush(); it.clear() }
-        def reloaded = Author.findByName("Batch Author")
+        def reloaded = Author.findByName('Batch Author')
 
         then: "all books updated"
         reloaded.books.every { !it.inStock }
@@ -312,9 +312,9 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test addTo creates bidirectional link"() {
         given: "an author and a book"
-        def author = new Author(name: "AddTo Author", email: "addto@author.com")
+        def author = new Author(name: 'AddTo Author', email: 'addto@author.com')
         author.save(flush: true)
-        def book = new Book(title: "AddTo Book", pageCount: 100, inStock: true)
+        def book = new Book(title: 'AddTo Book', pageCount: 100, inStock: true)
 
         when: "using addTo"
         author.addToBooks(book)
@@ -327,8 +327,8 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test removeFrom breaks bidirectional link"() {
         given: "an author with a book"
-        def author = new Author(name: "RemoveFrom Author", email: "remove@author.com")
-        def book = new Book(title: "RemoveFrom Book", pageCount: 100, inStock: true)
+        def author = new Author(name: 'RemoveFrom Author', email: 'remove@author.com')
+        def book = new Book(title: 'RemoveFrom Book', pageCount: 100, inStock: true)
         author.addToBooks(book)
         author.save(flush: true)
 
@@ -342,16 +342,16 @@ class GormCascadeOperationsSpec extends Specification {
 
     void "test collection operations on hasMany"() {
         given: "a city with users"
-        def city = new City(name: "Collection City")
-        city.addToUsers(new User(name: "User1"))
-        city.addToUsers(new User(name: "User2"))
-        city.addToUsers(new User(name: "User3"))
+        def city = new City(name: 'Collection City')
+        city.addToUsers(new User(name: 'User1'))
+        city.addToUsers(new User(name: 'User2'))
+        city.addToUsers(new User(name: 'User3'))
         city.save(flush: true)
 
         expect: "collection operations work"
         city.users.size() == 3
-        city.users.find { it.name == "User1" } != null
-        city.users.findAll { it.name.startsWith("User") }.size() == 3
-        city.users.collect { it.name }.containsAll(["User1", "User2", "User3"])
+        city.users.find { it.name == 'User1' } != null
+        city.users.findAll { it.name.startsWith('User') }.size() == 3
+        city.users.collect { it.name }.containsAll(['User1', 'User2', 'User3'])
     }
 }
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCriteriaQueriesSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCriteriaQueriesSpec.groovy
index d41e02b64b..b73c87d977 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCriteriaQueriesSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormCriteriaQueriesSpec.groovy
@@ -16,14 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
+import spock.lang.Specification
+import spock.lang.Unroll
+
 import grails.gorm.DetachedCriteria
 import grails.gorm.transactions.Rollback
 import grails.testing.mixin.integration.Integration
-import spock.lang.Specification
-import spock.lang.Unroll
 
 /**
  * Tests for GORM Criteria Queries - both createCriteria() and DetachedCriteria.
@@ -31,34 +31,34 @@ import spock.lang.Unroll
  * Criteria queries provide a type-safe, programmatic way to build
  * complex queries without writing HQL strings.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class GormCriteriaQueriesSpec extends Specification {
 
     def setup() {
         // Clean up and create fresh test data
-        Book.executeUpdate("delete from Book")
-        Author.executeUpdate("delete from Author")
+        Book.executeUpdate('delete from Book')
+        Author.executeUpdate('delete from Author')
 
-        def kingAuthor = new Author(name: "Stephen King", email: "stephen@king.com").save(flush: true)
-        def clancyAuthor = new Author(name: "Tom Clancy", email: "tom@clancy.com").save(flush: true)
-        def grishamAuthor = new Author(name: "John Grisham", email: "john@grisham.com").save(flush: true)
+        def kingAuthor = new Author(name: 'Stephen King', email: 'stephen@king.com').save(flush: true)
+        def clancyAuthor = new Author(name: 'Tom Clancy', email: 'tom@clancy.com').save(flush: true)
+        def grishamAuthor = new Author(name: 'John Grisham', email: 'john@grisham.com').save(flush: true)
 
         // Stephen King books
-        new Book(title: "The Stand", isbn: "1234567890", pageCount: 1153, price: 19.99, inStock: true, author: kingAuthor).save(flush: true)
-        new Book(title: "It", isbn: "0987654321", pageCount: 1138, price: 18.99, inStock: true, author: kingAuthor).save(flush: true)
-        new Book(title: "The Shining", isbn: "1122334455", pageCount: 447, price: 14.99, inStock: false, author: kingAuthor).save(flush: true)
+        new Book(title: 'The Stand', isbn: '1234567890', pageCount: 1153, price: 19.99, inStock: true, author: kingAuthor).save(flush: true)
+        new Book(title: 'It', isbn: '0987654321', pageCount: 1138, price: 18.99, inStock: true, author: kingAuthor).save(flush: true)
+        new Book(title: 'The Shining', isbn: '1122334455', pageCount: 447, price: 14.99, inStock: false, author: kingAuthor).save(flush: true)
 
         // Tom Clancy books
-        new Book(title: "The Hunt for Red October", isbn: "2233445566", pageCount: 387, price: 16.99, inStock: true, author: clancyAuthor).save(flush: true)
-        new Book(title: "Patriot Games", isbn: "3344556677", pageCount: 540, price: 15.99, inStock: false, author: clancyAuthor).save(flush: true)
+        new Book(title: 'The Hunt for Red October', isbn: '2233445566', pageCount: 387, price: 16.99, inStock: true, author: clancyAuthor).save(flush: true)
+        new Book(title: 'Patriot Games', isbn: '3344556677', pageCount: 540, price: 15.99, inStock: false, author: clancyAuthor).save(flush: true)
 
         // John Grisham books
-        new Book(title: "The Firm", isbn: "4455667788", pageCount: 421, price: 13.99, inStock: true, author: grishamAuthor).save(flush: true)
-        new Book(title: "A Time to Kill", isbn: "5566778899", pageCount: 515, price: 14.99, inStock: true, author: grishamAuthor).save(flush: true)
+        new Book(title: 'The Firm', isbn: '4455667788', pageCount: 421, price: 13.99, inStock: true, author: grishamAuthor).save(flush: true)
+        new Book(title: 'A Time to Kill', isbn: '5566778899', pageCount: 515, price: 14.99, inStock: true, author: grishamAuthor).save(flush: true)
 
         // Book without author
-        new Book(title: "Anonymous Work", pageCount: 100, price: 9.99, inStock: true).save(flush: true)
+        new Book(title: 'Anonymous Work', pageCount: 100, price: 9.99, inStock: true).save(flush: true)
     }
 
     // ============================================
@@ -83,7 +83,7 @@ class GormCriteriaQueriesSpec extends Specification {
 
         then: "exact match found"
         results.size() == 1
-        results[0].title == "The Stand"
+        results[0].title == 'The Stand'
     }
 
     void "test criteria with like restriction"() {
@@ -94,7 +94,7 @@ class GormCriteriaQueriesSpec extends Specification {
 
         then: "matching books found"
         results.size() == 4  // The Stand, The Shining, The Hunt..., The Firm
-        results.every { it.title.startsWith("The") }
+        results.every { it.title.startsWith('The') }
     }
 
     void "test criteria with ilike (case insensitive)"() {
@@ -148,7 +148,7 @@ class GormCriteriaQueriesSpec extends Specification {
 
         then: "books without ISBN found"
         results.size() == 1
-        results[0].title == "Anonymous Work"
+        results[0].title == 'Anonymous Work'
     }
 
     void "test criteria with isNotNull"() {
@@ -499,7 +499,7 @@ class GormCriteriaQueriesSpec extends Specification {
     void "test HQL with named parameters"() {
         when: "executing HQL with named params"
         def results = Book.executeQuery(
-            "from Book b where b.price > :minPrice and b.inStock = :stock",
+            'from Book b where b.price > :minPrice and b.inStock = :stock',
             [minPrice: 15.00, stock: true]
         )
 
@@ -510,19 +510,19 @@ class GormCriteriaQueriesSpec extends Specification {
     void "test HQL with positional parameters"() {
         when: "executing HQL with named parameter as alternative to positional"
         def results = Book.executeQuery(
-            "from Book b where b.title like :pattern",
+            'from Book b where b.title like :pattern',
             [pattern: 'The%']
         )
 
         then: "results match"
         results.size() == 4
-        results.every { it.title.startsWith("The") }
+        results.every { it.title.startsWith('The') }
     }
 
     void "test HQL with pagination"() {
         when: "executing paginated HQL"
         def results = Book.executeQuery(
-            "from Book b order by b.title",
+            'from Book b order by b.title',
             [max: 3, offset: 0]
         )
 
@@ -533,7 +533,7 @@ class GormCriteriaQueriesSpec extends Specification {
     void "test HQL join query"() {
         when: "executing HQL join"
         def results = Book.executeQuery(
-            "select b from Book b join b.author a where a.name = :authorName",
+            'select b from Book b join b.author a where a.name = :authorName',
             [authorName: 'Stephen King']
         )
 
@@ -545,7 +545,7 @@ class GormCriteriaQueriesSpec extends Specification {
     void "test HQL aggregate functions"() {
         when: "executing HQL aggregates"
         def result = Book.executeQuery(
-            "select count(b), avg(b.price), max(b.pageCount) from Book b"
+            'select count(b), avg(b.price), max(b.pageCount) from Book b'
         )[0]
 
         then: "aggregates calculated"
@@ -557,7 +557,7 @@ class GormCriteriaQueriesSpec extends Specification {
     void "test HQL group by"() {
         when: "executing HQL group by"
         def results = Book.executeQuery(
-            "select a.name, count(b) from Book b join b.author a group by a.name order by count(b) desc"
+            'select a.name, count(b) from Book b join b.author a group by a.name order by count(b) desc'
         )
 
         then: "grouped results"
@@ -569,7 +569,7 @@ class GormCriteriaQueriesSpec extends Specification {
     void "test executeUpdate for bulk operations"() {
         when: "executing bulk update"
         int updated = Book.executeUpdate(
-            "update Book b set b.price = b.price * 1.1 where b.inStock = true"
+            'update Book b set b.price = b.price * 1.1 where b.inStock = true'
         )
 
         then: "bulk update applied"
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormDataServicesSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormDataServicesSpec.groovy
index 7359e96196..4a6b8c5026 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormDataServicesSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormDataServicesSpec.groovy
@@ -16,15 +16,16 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
-import grails.gorm.transactions.Rollback
-import grails.testing.mixin.integration.Integration
-import org.springframework.beans.factory.annotation.Autowired
 import spock.lang.Specification
 import spock.lang.Unroll
 
+import org.springframework.beans.factory.annotation.Autowired
+
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
+
 /**
  * Tests for GORM Data Services - abstract class-based services with
  * automatically generated implementations for CRUD and finder methods.
@@ -32,8 +33,8 @@ import spock.lang.Unroll
  * Data Services are a powerful feature of GORM that generates
  * service implementations at compile time based on method signatures.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class GormDataServicesSpec extends Specification {
 
     @Autowired
@@ -41,16 +42,16 @@ class GormDataServicesSpec extends Specification {
 
     def setup() {
         // Clean up and create fresh test data
-        Book.executeUpdate("delete from Book")
-        Author.executeUpdate("delete from Author")
+        Book.executeUpdate('delete from Book')
+        Author.executeUpdate('delete from Author')
 
-        def author = new Author(name: "Stephen King", email: "stephen@king.com").save(flush: true)
+        def author = new Author(name: 'Stephen King', email: 'stephen@king.com').save(flush: true)
 
-        new Book(title: "The Stand", isbn: "1234567890", pageCount: 1153, price: 19.99, inStock: true, author: author).save(flush: true)
-        new Book(title: "It", isbn: "0987654321", pageCount: 1138, price: 18.99, inStock: true, author: author).save(flush: true)
-        new Book(title: "The Shining", isbn: "1122334455", pageCount: 447, price: 14.99, inStock: false, author: author).save(flush: true)
-        new Book(title: "Carrie", isbn: "5566778899", pageCount: 199, price: 12.99, inStock: true).save(flush: true)
-        new Book(title: "Salem's Lot", pageCount: 439, price: 15.99, inStock: false).save(flush: true)
+        new Book(title: 'The Stand', isbn: '1234567890', pageCount: 1153, price: 19.99, inStock: true, author: author).save(flush: true)
+        new Book(title: 'It', isbn: '0987654321', pageCount: 1138, price: 18.99, inStock: true, author: author).save(flush: true)
+        new Book(title: 'The Shining', isbn: '1122334455', pageCount: 447, price: 14.99, inStock: false, author: author).save(flush: true)
+        new Book(title: 'Carrie', isbn: '5566778899', pageCount: 199, price: 12.99, inStock: true).save(flush: true)
+        new Book(title: 'Salem\'s Lot', pageCount: 439, price: 15.99, inStock: false).save(flush: true)
     }
 
     // ============================================
@@ -59,15 +60,15 @@ class GormDataServicesSpec extends Specification {
 
     void "test get by id"() {
         given: "an existing book"
-        def book = Book.findByTitle("The Stand")
+        def book = Book.findByTitle('The Stand')
 
         when: "retrieving by id through data service"
         def result = bookDataService.get(book.id)
 
         then: "the book is found"
         result != null
-        result.title == "The Stand"
-        result.isbn == "1234567890"
+        result.title == 'The Stand'
+        result.isbn == '1234567890'
     }
 
     void "test list with pagination"() {
@@ -85,20 +86,20 @@ class GormDataServicesSpec extends Specification {
 
     void "test save new book"() {
         given: "a new book"
-        def book = new Book(title: "Doctor Sleep", pageCount: 531, price: 16.99, inStock: true)
+        def book = new Book(title: 'Doctor Sleep', pageCount: 531, price: 16.99, inStock: true)
 
         when: "saving through data service"
         def saved = bookDataService.save(book)
 
         then: "book is persisted"
         saved.id != null
-        saved.title == "Doctor Sleep"
+        saved.title == 'Doctor Sleep'
         bookDataService.count() == 6
     }
 
     void "test delete"() {
         given: "an existing book"
-        def book = Book.findByTitle("Carrie")
+        def book = Book.findByTitle('Carrie')
         def bookId = book.id
 
         when: "deleting through data service"
@@ -107,7 +108,7 @@ class GormDataServicesSpec extends Specification {
 
         then: "book is removed"
         Book.get(bookId) == null
-        bookDataService.findByTitle("Carrie") == null
+        bookDataService.findByTitle('Carrie') == null
     }
 
     // ============================================
@@ -116,18 +117,18 @@ class GormDataServicesSpec extends Specification {
 
     void "test findByTitle"() {
         expect: "finding by title works"
-        bookDataService.findByTitle("It") != null
-        bookDataService.findByTitle("It").isbn == "0987654321"
-        bookDataService.findByTitle("NonExistent") == null
+        bookDataService.findByTitle('It') != null
+        bookDataService.findByTitle('It').isbn == '0987654321'
+        bookDataService.findByTitle('NonExistent') == null
     }
 
     void "test findAllByTitle"() {
         when: "finding all by title"
-        def results = bookDataService.findAllByTitle("The Stand")
+        def results = bookDataService.findAllByTitle('The Stand')
 
         then: "returns matching books"
         results.size() == 1
-        results[0].title == "The Stand"
+        results[0].title == 'The Stand'
     }
 
     void "test findAllByInStock"() {
@@ -166,29 +167,29 @@ class GormDataServicesSpec extends Specification {
 
     void "test existsByTitle (manual implementation)"() {
         expect: "exists queries work via manual implementation"
-        bookDataService.existsByTitle("It") == true
-        bookDataService.existsByTitle("NonExistent") == false
+        bookDataService.existsByTitle('It') == true
+        bookDataService.existsByTitle('NonExistent') == false
     }
 
     void "test findByIsbnValue for nullable field"() {
         expect: "finding by nullable isbn works via manual HQL"
-        bookDataService.findByIsbnValue("1234567890") != null
-        bookDataService.findByIsbnValue("1234567890").title == "The Stand"
-        bookDataService.findByIsbnValue("0000000000") == null
+        bookDataService.findByIsbnValue('1234567890') != null
+        bookDataService.findByIsbnValue('1234567890').title == 'The Stand'
+        bookDataService.findByIsbnValue('0000000000') == null
         bookDataService.findByIsbnValue(null) == null
     }
 
     void "test countByTitleLike"() {
         expect: "count with like pattern works"
-        bookDataService.countByTitleLike("The%") == 2  // "The Stand", "The Shining"
-        bookDataService.countByTitleLike("%Lot") == 1  // "Salem's Lot"
+        bookDataService.countByTitleLike('The%') == 2  // 'The Stand', 'The Shining'
+        bookDataService.countByTitleLike('%Lot') == 1  // "Salem's Lot"
     }
 
     void "test findByTitleAndOptionalIsbn"() {
         expect: "finding with optional isbn works"
-        bookDataService.findByTitleAndOptionalIsbn("The Stand", "1234567890") != null
-        bookDataService.findByTitleAndOptionalIsbn("The Stand", "wrong-isbn") == null
-        bookDataService.findByTitleAndOptionalIsbn("The Stand", null)?.title == "The Stand"
+        bookDataService.findByTitleAndOptionalIsbn('The Stand', '1234567890') != null
+        bookDataService.findByTitleAndOptionalIsbn('The Stand', 'wrong-isbn') == null
+        bookDataService.findByTitleAndOptionalIsbn('The Stand', null)?.title == 'The Stand'
     }
 
     // ============================================
@@ -197,11 +198,11 @@ class GormDataServicesSpec extends Specification {
 
     void "test findByTitlePattern with regex-like pattern"() {
         when: "searching with pattern"
-        def results = bookDataService.findByTitlePattern("The%")
+        def results = bookDataService.findByTitlePattern('The%')
 
         then: "matching books are found"
         results.size() == 2
-        results*.title.every { it.startsWith("The") }
+        results*.title.every { it.startsWith('The') }
     }
 
     void "test findByPageRange"() {
@@ -219,7 +220,7 @@ class GormDataServicesSpec extends Specification {
 
         then: "matching books are found"
         results.size() == 1  // Only Carrie at 12.99 is in stock and under 15
-        results[0].title == "Carrie"
+        results[0].title == 'Carrie'
     }
 
     // ============================================
@@ -228,13 +229,13 @@ class GormDataServicesSpec extends Specification {
 
     void "test searchByTitleHql"() {
         when: "searching with HQL pattern"
-        def results = bookDataService.searchByTitleHql("The%")
+        def results = bookDataService.searchByTitleHql('The%')
 
         then: "results are found and ordered"
         results.size() == 2
         // Ordered by title
-        results[0].title == "The Shining"
-        results[1].title == "The Stand"
+        results[0].title == 'The Shining'
+        results[1].title == 'The Stand'
     }
 
     void "test countBooksWithAuthor"() {
@@ -248,7 +249,7 @@ class GormDataServicesSpec extends Specification {
 
         then: "all titles returned"
         titles.size() == 5
-        titles.containsAll(["The Stand", "It", "The Shining", "Carrie", "Salem's Lot"])
+        titles.containsAll(['The Stand', 'It', 'The Shining', 'Carrie', 'Salem\'s Lot'])
     }
 
     // ============================================
@@ -257,13 +258,13 @@ class GormDataServicesSpec extends Specification {
 
     void "test updateStockStatus"() {
         given: "an out of stock book"
-        def book = Book.findByTitle("The Shining")
+        def book = Book.findByTitle('The Shining')
         assert book.inStock == false
 
         when: "updating stock status"
         def updated = bookDataService.updateStockStatus(book.id, true)
         Book.withSession { it.flush(); it.clear() }
-        book = Book.findByTitle("The Shining")
+        book = Book.findByTitle('The Shining')
 
         then: "update is applied"
         updated == 1
@@ -276,11 +277,11 @@ class GormDataServicesSpec extends Specification {
 
     void "test deleteByTitle"() {
         when: "deleting by title"
-        def deleted = bookDataService.deleteByTitle("Carrie")
+        def deleted = bookDataService.deleteByTitle('Carrie')
 
         then: "book is deleted"
         deleted == 1
-        Book.findByTitle("Carrie") == null
+        Book.findByTitle('Carrie') == null
         bookDataService.count() == 4
     }
 
@@ -329,9 +330,9 @@ class GormDataServicesSpec extends Specification {
 
         where:
         title           | expectedFound
-        "The Stand"     | true
-        "It"            | true
-        ""              | false
-        "NONEXISTENT"   | false
+        'The Stand'     | true
+        'It'            | true
+        ''              | false
+        'NONEXISTENT'   | false
     }
 }
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormEventsSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormEventsSpec.groovy
index c28c8f071b..2f9dd463bb 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormEventsSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/GormEventsSpec.groovy
@@ -16,12 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
+import spock.lang.Specification
+
 import grails.gorm.transactions.Rollback
 import grails.testing.mixin.integration.Integration
-import spock.lang.Specification
 
 /**
  * Tests for GORM Event Listeners.
@@ -37,12 +37,12 @@ import spock.lang.Specification
  * Note: These tests focus on entity state changes rather than static event logs
  * to avoid test isolation issues with parallel test execution.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class GormEventsSpec extends Specification {
 
     def setup() {
-        AuditedEntity.executeUpdate("delete from AuditedEntity")
+        AuditedEntity.executeUpdate('delete from AuditedEntity')
     }
 
     // ============================================
@@ -51,24 +51,24 @@ class GormEventsSpec extends Specification {
 
     void "test beforeValidate is called during validation"() {
         given: "an entity with untrimmed name"
-        def entity = new AuditedEntity(name: "  Test Entity  ")
+        def entity = new AuditedEntity(name: '  Test Entity  ')
 
         when: "validating the entity"
         entity.validate()
 
         then: "beforeValidate was called and name was trimmed"
         entity.wasValidated == true
-        entity.name == "Test Entity"
+        entity.name == 'Test Entity'
     }
 
     void "test beforeValidate is called before save validation"() {
         when: "saving an entity"
-        def entity = new AuditedEntity(name: "  BeforeValidate Test  ")
+        def entity = new AuditedEntity(name: '  BeforeValidate Test  ')
         entity.save(flush: true)
 
         then: "beforeValidate was called"
         entity.wasValidated == true
-        entity.name == "BeforeValidate Test"  // Trimmed
+        entity.name == 'BeforeValidate Test'  // Trimmed
     }
 
     // ============================================
@@ -77,14 +77,14 @@ class GormEventsSpec extends Specification {
 
     void "test beforeInsert sets audit fields"() {
         when: "saving a new entity"
-        def entity = new AuditedEntity(name: "Insert Test")
+        def entity = new AuditedEntity(name: 'Insert Test')
         entity.save(flush: true)
 
         then: "beforeInsert set the audit fields"
         entity.dateCreated != null
         entity.lastUpdated != null
-        entity.createdBy == "test-user"
-        entity.updatedBy == "test-user"
+        entity.createdBy == 'test-user'
+        entity.updatedBy == 'test-user'
     }
 
     void "test beforeInsert and afterInsert event order"() {
@@ -95,13 +95,13 @@ class GormEventsSpec extends Specification {
         then: "entity was persisted with ID (proving events fired)"
         entity.id != null
         entity.dateCreated != null
-        entity.createdBy == "test-user"
+        entity.createdBy == 'test-user'
         entity.wasValidated == true
     }
 
     void "test afterInsert is called after entity is persisted"() {
         when: "saving a new entity"
-        def entity = new AuditedEntity(name: "AfterInsert")
+        def entity = new AuditedEntity(name: 'AfterInsert')
         entity.save(flush: true)
 
         then: "entity was persisted"
@@ -115,13 +115,13 @@ class GormEventsSpec extends Specification {
 
     void "test beforeUpdate sets lastUpdated"() {
         given: "an existing entity"
-        def entity = new AuditedEntity(name: "Update Test")
+        def entity = new AuditedEntity(name: 'Update Test')
         entity.save(flush: true)
         def originalUpdated = entity.lastUpdated
 
         when: "updating the entity"
         sleep(10)  // Ensure time difference
-        entity.description = "Updated description"
+        entity.description = 'Updated description'
         entity.save(flush: true)
 
         then: "beforeUpdate updated lastUpdated"
@@ -131,35 +131,35 @@ class GormEventsSpec extends Specification {
 
     void "test beforeUpdate and afterUpdate event order"() {
         given: "an existing entity"
-        def entity = new AuditedEntity(name: "UpdateOrder")
+        def entity = new AuditedEntity(name: 'UpdateOrder')
         entity.save(flush: true)
         def originalUpdated = entity.lastUpdated
 
         when: "updating the entity"
         sleep(10)
-        entity.description = "Changed"
+        entity.description = 'Changed'
         entity.save(flush: true)
 
         then: "events fired - lastUpdated was modified by beforeUpdate"
         entity.lastUpdated > originalUpdated
         entity.updateCount == 1
-        entity.updatedBy == "test-user"
+        entity.updatedBy == 'test-user'
     }
 
     void "test beforeUpdate can cancel update by returning false"() {
         given: "an entity marked as DELETED"
-        def entity = new AuditedEntity(name: "Deleted Entity", status: "DELETED")
+        def entity = new AuditedEntity(name: 'Deleted Entity', status: 'DELETED')
         entity.save(flush: true)
         def originalDescription = entity.description
         def originalUpdateCount = entity.updateCount
 
         when: "attempting to update DELETED entity"
-        entity.description = "Trying to change"
+        entity.description = 'Trying to change'
         entity.save(flush: true)
 
         // Clear session to reload
         AuditedEntity.withSession { it.flush(); it.clear() }
-        def reloaded = AuditedEntity.findByName("Deleted Entity")
+        def reloaded = AuditedEntity.findByName('Deleted Entity')
 
         then: "update was cancelled - description unchanged"
         reloaded.description == originalDescription
@@ -168,18 +168,18 @@ class GormEventsSpec extends Specification {
 
     void "test updateCount increments on each update"() {
         given: "a new entity"
-        def entity = new AuditedEntity(name: "MultiUpdate")
+        def entity = new AuditedEntity(name: 'MultiUpdate')
         entity.save(flush: true)
         assert entity.updateCount == 0
 
         when: "updating multiple times"
-        entity.description = "First update"
+        entity.description = 'First update'
         entity.save(flush: true)
 
-        entity.description = "Second update"
+        entity.description = 'Second update'
         entity.save(flush: true)
 
-        entity.description = "Third update"
+        entity.description = 'Third update'
         entity.save(flush: true)
 
         then: "updateCount tracks all updates"
@@ -192,7 +192,7 @@ class GormEventsSpec extends Specification {
 
     void "test beforeDelete is called before deletion"() {
         given: "an existing entity"
-        def entity = new AuditedEntity(name: "Delete Test")
+        def entity = new AuditedEntity(name: 'Delete Test')
         entity.save(flush: true)
         def entityId = entity.id
 
@@ -205,7 +205,7 @@ class GormEventsSpec extends Specification {
 
     void "test afterDelete is called after deletion"() {
         given: "an existing entity"
-        def entity = new AuditedEntity(name: "AfterDelete")
+        def entity = new AuditedEntity(name: 'AfterDelete')
         entity.save(flush: true)
         def entityId = entity.id
 
@@ -218,7 +218,7 @@ class GormEventsSpec extends Specification {
 
     void "test delete removes entity from database"() {
         given: "an existing entity"
-        def entity = new AuditedEntity(name: "DeleteOrder")
+        def entity = new AuditedEntity(name: 'DeleteOrder')
         entity.save(flush: true)
         def entityId = entity.id
 
@@ -227,7 +227,7 @@ class GormEventsSpec extends Specification {
 
         then: "entity is gone"
         AuditedEntity.get(entityId) == null
-        AuditedEntity.findByName("DeleteOrder") == null
+        AuditedEntity.findByName('DeleteOrder') == null
     }
 
     // ============================================
@@ -236,7 +236,7 @@ class GormEventsSpec extends Specification {
 
     void "test entity can be loaded from database"() {
         given: "a persisted entity"
-        def entity = new AuditedEntity(name: "Load Test")
+        def entity = new AuditedEntity(name: 'Load Test')
         entity.save(flush: true)
         def entityId = entity.id
 
@@ -248,15 +248,15 @@ class GormEventsSpec extends Specification {
 
         then: "entity is loaded correctly"
         loaded != null
-        loaded.name == "Load Test"
+        loaded.name == 'Load Test'
         loaded.id == entityId
     }
 
     void "test list loads multiple entities from database"() {
         given: "multiple persisted entities"
-        new AuditedEntity(name: "Load1").save(flush: true)
-        new AuditedEntity(name: "Load2").save(flush: true)
-        new AuditedEntity(name: "Load3").save(flush: true)
+        new AuditedEntity(name: 'Load1').save(flush: true)
+        new AuditedEntity(name: 'Load2').save(flush: true)
+        new AuditedEntity(name: 'Load3').save(flush: true)
 
         // Clear session to force reload
         AuditedEntity.withSession { it.flush(); it.clear() }
@@ -266,7 +266,7 @@ class GormEventsSpec extends Specification {
 
         then: "all entities are loaded"
         entities.size() == 3
-        entities*.name.containsAll(["Load1", "Load2", "Load3"])
+        entities*.name.containsAll(['Load1', 'Load2', 'Load3'])
     }
 
     // ============================================
@@ -275,19 +275,19 @@ class GormEventsSpec extends Specification {
 
     void "test full entity lifecycle"() {
         when: "creating an entity"
-        def entity = new AuditedEntity(name: "Lifecycle")
+        def entity = new AuditedEntity(name: 'Lifecycle')
         entity.save(flush: true)
 
         then: "insert lifecycle completed"
         entity.id != null
         entity.dateCreated != null
-        entity.createdBy == "test-user"
+        entity.createdBy == 'test-user'
         entity.wasValidated == true
 
         when: "updating the entity"
         def originalUpdated = entity.lastUpdated
         sleep(10)
-        entity.description = "Updated"
+        entity.description = 'Updated'
         entity.save(flush: true)
 
         then: "update lifecycle completed"
@@ -304,7 +304,7 @@ class GormEventsSpec extends Specification {
 
     void "test event firing does not occur for failed validation"() {
         given: "an invalid entity (blank name)"
-        def entity = new AuditedEntity(name: "")
+        def entity = new AuditedEntity(name: '')
 
         when: "attempting to save"
         def saved = entity.save()
@@ -316,15 +316,15 @@ class GormEventsSpec extends Specification {
 
     void "test multiple entities can be saved"() {
         when: "saving multiple entities"
-        def e1 = new AuditedEntity(name: "Entity1").save(flush: true)
-        def e2 = new AuditedEntity(name: "Entity2").save(flush: true)
-        def e3 = new AuditedEntity(name: "Entity3").save(flush: true)
+        def e1 = new AuditedEntity(name: 'Entity1').save(flush: true)
+        def e2 = new AuditedEntity(name: 'Entity2').save(flush: true)
+        def e3 = new AuditedEntity(name: 'Entity3').save(flush: true)
 
         then: "all entities saved with audit fields"
         e1.id != null
         e2.id != null
         e3.id != null
-        [e1, e2, e3].every { it.dateCreated != null && it.createdBy == "test-user" }
+        [e1, e2, e3].every { it.dateCreated != null && it.createdBy == 'test-user' }
     }
 
     // ============================================
@@ -333,26 +333,26 @@ class GormEventsSpec extends Specification {
 
     void "test audit fields are automatically populated on insert"() {
         when: "saving a new entity"
-        def entity = new AuditedEntity(name: "Audit Test")
+        def entity = new AuditedEntity(name: 'Audit Test')
         entity.save(flush: true)
 
         then: "all audit fields are set"
         entity.dateCreated != null
         entity.lastUpdated != null
-        entity.createdBy == "test-user"
-        entity.updatedBy == "test-user"
+        entity.createdBy == 'test-user'
+        entity.updatedBy == 'test-user'
     }
 
     void "test audit fields are updated on update"() {
         given: "an existing entity"
-        def entity = new AuditedEntity(name: "Audit Update")
+        def entity = new AuditedEntity(name: 'Audit Update')
         entity.save(flush: true)
         def originalCreated = entity.dateCreated
         def originalUpdated = entity.lastUpdated
 
         when: "updating the entity"
         sleep(10)
-        entity.description = "Changed"
+        entity.description = 'Changed'
         entity.save(flush: true)
 
         then: "dateCreated unchanged, lastUpdated modified"
@@ -362,16 +362,16 @@ class GormEventsSpec extends Specification {
 
     void "test name trimming in beforeValidate"() {
         when: "saving entities with various whitespace"
-        def e1 = new AuditedEntity(name: "  leading spaces")
-        def e2 = new AuditedEntity(name: "trailing spaces  ")
-        def e3 = new AuditedEntity(name: "  both sides  ")
+        def e1 = new AuditedEntity(name: '  leading spaces')
+        def e2 = new AuditedEntity(name: 'trailing spaces  ')
+        def e3 = new AuditedEntity(name: '  both sides  ')
         e1.save(flush: true)
         e2.save(flush: true)
         e3.save(flush: true)
 
         then: "all names are trimmed"
-        e1.name == "leading spaces"
-        e2.name == "trailing spaces"
-        e3.name == "both sides"
+        e1.name == 'leading spaces'
+        e2.name == 'trailing spaces'
+        e3.name == 'both sides'
     }
 }
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/ScaffoldingFunctionalSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/ScaffoldingFunctionalSpec.groovy
index dbead79c9b..3ce0108b50 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/ScaffoldingFunctionalSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/ScaffoldingFunctionalSpec.groovy
@@ -16,26 +16,32 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
+import gorm.pages.AuthorCreatePage
+import gorm.pages.AuthorListPage
+import gorm.pages.AuthorShowPage
+import gorm.pages.BookCreatePage
+import gorm.pages.BookListPage
+import gorm.pages.BookShowPage
+import spock.lang.Shared
+import spock.lang.Stepwise
+
 import grails.plugin.geb.ContainerGebSpec
 import grails.testing.mixin.integration.Integration
-import gorm.pages.*
-import spock.lang.Stepwise
 
 /**
  * Functional tests for Author and Book scaffolding in the gorm test app.
  * 
  * Tests CRUD operations and relationship handling between Author and Book entities.
  */
-@Integration
 @Stepwise
+@Integration
 class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     // Store created entity IDs for use across @Stepwise tests
-    @spock.lang.Shared String authorId
-    @spock.lang.Shared String bookId
+    @Shared String authorId
+    @Shared String bookId
 
     def "author list page displays"() {
         when: "navigating to author list"
@@ -47,14 +53,14 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "can create new author"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "filling in author details"
-        name = 'Jane Austen'
-        email = 'jane.austen@example.com'
+        page.name = 'Jane Austen'
+        page.email = 'jane.austen@example.com'
 
         and: "submitting the form"
-        createButton.click()
+        page.createButton.click()
 
         then: "author is created and show page displayed"
         waitFor {
@@ -107,10 +113,10 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "can create new book with author association"() {
         when: "navigating to create book page"
-        to BookCreatePage
+        def page = to BookCreatePage
 
         and: "filling in book details"
-        titleField = 'Pride and Prejudice'
+        page.titleField = 'Pride and Prejudice'
         
         // Select author if dropdown exists
         if ($('select[name="author.id"]').displayed || $('select[name=author]').displayed) {
@@ -121,7 +127,7 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
         }
 
         and: "submitting the form"
-        createButton.click()
+        page.createButton.click()
 
         then: "book is created"
         waitFor {
@@ -166,12 +172,12 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "validation errors displayed for invalid author"() {
         when: "navigating to create author page"
-        to AuthorCreatePage
+        def page = to AuthorCreatePage
 
         and: "submitting with empty required fields"
-        name = ''
-        email = 'invalid-email'
-        createButton.click()
+        page.name = ''
+        page.email = 'invalid-email'
+        page.createButton.click()
 
         then: "validation errors are displayed"
         waitFor {
@@ -186,11 +192,11 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "validation errors displayed for invalid book"() {
         when: "navigating to create book page"
-        to BookCreatePage
+        def page = to BookCreatePage
 
         and: "submitting with empty required fields"
-        titleField = ''
-        createButton.click()
+        page.titleField = ''
+        page.createButton.click()
 
         then: "validation errors are displayed"
         waitFor {
@@ -205,9 +211,9 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "can delete book"() {
         given: "create a book to delete"
-        to BookCreatePage
-        titleField = 'Book To Delete'
-        createButton.click()
+        def page = to BookCreatePage
+        page.titleField = 'Book To Delete'
+        page.createButton.click()
         waitFor { currentUrl.contains('/book/show/') }
 
         when: "clicking delete button"
@@ -229,10 +235,10 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "can delete author"() {
         given: "create an author to delete"
-        to AuthorCreatePage
-        name = 'Author To Delete'
-        email = 'delete.me@example.com'
-        createButton.click()
+        def page = to AuthorCreatePage
+        page.name = 'Author To Delete'
+        page.email = 'delete.me@example.com'
+        page.createButton.click()
         waitFor { currentUrl.contains('/author/show/') }
 
         when: "clicking delete button"
@@ -262,21 +268,21 @@ class ScaffoldingFunctionalSpec extends ContainerGebSpec {
 
     def "author hasMany books relationship displayed on show page"() {
         given: "create author with book"
-        to AuthorCreatePage
-        name = 'Charles Dickens'
-        email = 'charles.dickens@example.com'
-        createButton.click()
+        def page = to AuthorCreatePage
+        page.name = 'Charles Dickens'
+        page.email = 'charles.dickens@example.com'
+        page.createButton.click()
         waitFor { currentUrl.contains('/author/show/') }
         def authorShowUrl = currentUrl
 
         and: "create book for this author"
-        to BookCreatePage
-        titleField = 'A Tale of Two Cities'
+        page = to BookCreatePage
+        page.titleField = 'A Tale of Two Cities'
         def authorSelect = $('select[name="author.id"]') ?: $('select[name=author]')
         if (authorSelect?.displayed) {
             authorSelect.find('option').last().click()
         }
-        createButton.click()
+        page.createButton.click()
 
         when: "viewing author show page"
         go authorShowUrl
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/UserSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/UserSpec.groovy
index d132f7265a..43571df20a 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/UserSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/UserSpec.groovy
@@ -16,16 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
+import spock.lang.Specification
+
+import org.springframework.beans.factory.annotation.Autowired
+
 import grails.gorm.transactions.Rollback
 import grails.testing.mixin.integration.Integration
-import org.springframework.beans.factory.annotation.Autowired
-import spock.lang.*
 
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class UserSpec extends Specification {
 
     @Autowired
@@ -34,16 +35,16 @@ class UserSpec extends Specification {
     void "Test where query over association id works"() {
         given: "Cities and users are set up"
             // Create test data within the test to ensure it exists
-            def london = City.findByName("London") ?: new City(name: "London")
+            def london = City.findByName('London') ?: new City(name: 'London')
             if (!london.id) {
-                london.addToUsers(name: "Bob")
-                london.addToUsers(name: "Fred")
+                london.addToUsers(name: 'Bob')
+                london.addToUsers(name: 'Fred')
                 london.save(flush: true)
             }
 
-            def paris = City.findByName("Paris") ?: new City(name: "Paris")
+            def paris = City.findByName('Paris') ?: new City(name: 'Paris')
             if (!paris.id) {
-                paris.addToUsers(name: "Joe")
+                paris.addToUsers(name: 'Joe')
                 paris.save(flush: true)
             }
 
diff --git a/grails-test-examples/gorm/src/integration-test/groovy/gorm/ValidationConstraintsSpec.groovy b/grails-test-examples/gorm/src/integration-test/groovy/gorm/ValidationConstraintsSpec.groovy
index ff937f23db..fa0562719d 100644
--- a/grails-test-examples/gorm/src/integration-test/groovy/gorm/ValidationConstraintsSpec.groovy
+++ b/grails-test-examples/gorm/src/integration-test/groovy/gorm/ValidationConstraintsSpec.groovy
@@ -16,14 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package gorm
 
-import grails.gorm.transactions.Rollback
-import grails.testing.mixin.integration.Integration
 import spock.lang.Specification
 import spock.lang.Unroll
 
+import grails.gorm.transactions.Rollback
+import grails.testing.mixin.integration.Integration
+import grails.validation.ValidationException
+
 /**
  * Comprehensive tests for GORM validation constraints.
  * 
@@ -39,8 +40,8 @@ import spock.lang.Unroll
  * - range: Tests numeric/date range constraints
  * - custom validators: Tests custom validation logic
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class ValidationConstraintsSpec extends Specification {
 
     // ============================================
@@ -145,11 +146,11 @@ class ValidationConstraintsSpec extends Specification {
         isValid == expectedValid
 
         where:
-        name                                                                                                          || expectedValid
-        'A'                                                                                                           || true   // Min length 1
-        'John Doe'                                                                                                    || true   // Normal length
-        'A' * 100                                                                                                     || true   // Max length 100
-        'A' * 101                                                                                                     || false  // Over max length
+        name       || expectedValid
+        'A'        || true   // Min length 1
+        'John Doe' || true   // Normal length
+        'A' * 100  || true   // Max length 100
+        'A' * 101  || false  // Over max length
     }
 
     // ============================================
@@ -174,14 +175,14 @@ class ValidationConstraintsSpec extends Specification {
         }
 
         where:
-        email                    || expectedValid
-        'valid@example.com'      || true
-        'user.name@domain.org'   || true
-        'user+tag@domain.com'    || true
-        'invalid-email'          || false
-        'missing@domain'         || false  // Missing TLD might fail
-        '@nodomain.com'          || false
-        ''                       || false  // Blank also fails
+        email                  || expectedValid
+        'valid@example.com'    || true
+        'user.name@domain.org' || true
+        'user+tag@domain.com'  || true
+        'invalid-email'        || false
+        'missing@domain'       || false  // Missing TLD might fail
+        '@nodomain.com'        || false
+        ''                     || false  // Blank also fails
     }
 
     // ============================================
@@ -256,14 +257,14 @@ class ValidationConstraintsSpec extends Specification {
         }
 
         where:
-        isbn              || expectedValid
-        null              || true   // nullable: true
-        '1234567890'      || true   // 10 digits
-        '1234567890123'   || true   // 13 digits
-        '123456789'       || false  // 9 digits - too short
-        '12345678901234'  || false  // 14 digits - too long
-        '123-456-789'     || false  // Has dashes
-        'ABCDEFGHIJ'      || false  // Letters
+        isbn             || expectedValid
+        null             || true   // nullable: true
+        '1234567890'     || true   // 10 digits
+        '1234567890123'  || true   // 13 digits
+        '123456789'      || false  // 9 digits - too short
+        '12345678901234' || false  // 14 digits - too long
+        '123-456-789'    || false  // Has dashes
+        'ABCDEFGHIJ'     || false  // Letters
     }
 
     // ============================================
@@ -441,7 +442,7 @@ class ValidationConstraintsSpec extends Specification {
         author.save(failOnError: true)
 
         then: "exception is thrown"
-        thrown(grails.validation.ValidationException)
+        thrown(ValidationException)
     }
 
     void "test save with validate false skips validation"() {
diff --git a/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautContextSpec.groovy b/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautContextSpec.groovy
index 219d42eeab..f0404a0e88 100644
--- a/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautContextSpec.groovy
+++ b/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautContextSpec.groovy
@@ -16,14 +16,18 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package micronaut
 
-import grails.testing.mixin.integration.Integration
-import io.micronaut.context.ApplicationContext
+import bean.injection.NamedService
+import io.micronaut.context.ApplicationContext as MicronautApplicationContext
+import spock.lang.Specification
+
 import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.context.ApplicationContext as SpringApplicationContext
 import org.springframework.context.ApplicationContextAware
-import spock.lang.Specification
+import org.springframework.context.ConfigurableApplicationContext
+
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for Micronaut context coexistence with Spring/Grails context.
@@ -38,11 +42,11 @@ import spock.lang.Specification
 class MicronautContextSpec extends Specification implements ApplicationContextAware {
 
     @Autowired
-    io.micronaut.context.ApplicationContext micronautContext
+    MicronautApplicationContext micronautContext
 
-    org.springframework.context.ApplicationContext springContext
+    SpringApplicationContext springContext
 
-    void setApplicationContext(org.springframework.context.ApplicationContext applicationContext) {
+    void setApplicationContext(SpringApplicationContext applicationContext) {
         this.springContext = applicationContext
     }
 
@@ -59,7 +63,7 @@ class MicronautContextSpec extends Specification implements ApplicationContextAw
 
     void "micronaut beans can be retrieved from micronaut context"() {
         when:
-        def beans = micronautContext.getBeansOfType(bean.injection.NamedService)
+        def beans = micronautContext.getBeansOfType(NamedService)
 
         then:
         beans != null
@@ -82,7 +86,7 @@ class MicronautContextSpec extends Specification implements ApplicationContextAw
 
     void "both contexts share the same application lifecycle"() {
         expect:
-        micronautContext.isRunning()
-        springContext.isActive()
+        micronautContext.running
+        (springContext as ConfigurableApplicationContext).active
     }
 }
diff --git a/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautQualifierSpec.groovy b/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautQualifierSpec.groovy
index 0b8ae0af16..bea5adfece 100644
--- a/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautQualifierSpec.groovy
+++ b/grails-test-examples/micronaut/src/integration-test/groovy/micronaut/MicronautQualifierSpec.groovy
@@ -19,15 +19,15 @@
 
 package micronaut
 
-import grails.testing.mixin.integration.Integration
-import org.springframework.beans.factory.annotation.Autowired
-import spock.lang.Specification
-
-import bean.injection.NamedService
 import bean.injection.PrimaryNamedService
+import bean.injection.QualifiedNamedService
 import bean.injection.RegularNamedService
 import bean.injection.SpecialNamedService
-import bean.injection.QualifiedNamedService
+import spock.lang.Specification
+
+import org.springframework.beans.factory.annotation.Autowired
+
+import grails.testing.mixin.integration.Integration
 
 /**
  * Integration tests for Micronaut bean qualifiers in Grails context.
diff --git a/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/Application.groovy b/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/Application.groovy
index b44eb32ee3..827e6e3116 100644
--- a/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/Application.groovy
+++ b/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/Application.groovy
@@ -19,9 +19,12 @@
 
 package scaffoldingfields
 
+import groovy.transform.CompileStatic
+
 import grails.boot.GrailsApp
 import grails.boot.config.GrailsAutoConfiguration
 
+@CompileStatic
 class Application extends GrailsAutoConfiguration {
     static void main(String[] args) {
         GrailsApp.run(Application)
diff --git a/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/BootStrap.groovy b/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/BootStrap.groovy
index 8a4e2fb108..d408d09f43 100644
--- a/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/BootStrap.groovy
+++ b/grails-test-examples/scaffolding-fields/grails-app/init/scaffoldingfields/BootStrap.groovy
@@ -19,93 +19,96 @@
 
 package scaffoldingfields
 
+import groovy.time.TimeCategory
+
 /**
  * Bootstrap data for testing scaffolding and fields functionality.
  */
 class BootStrap {
 
-    def init = { servletContext ->
-        // Create test departments
-        def engineering = new Department(name: 'Engineering', description: 'Software development team').save(failOnError: true)
-        def marketing = new Department(name: 'Marketing', description: 'Marketing and sales team').save(failOnError: true)
-        def hr = new Department(name: 'Human Resources', description: 'HR and recruitment').save(failOnError: true)
+    def init = {
+
+        use(TimeCategory) {
 
-        // Create test projects
-        def projectAlpha = new Project(name: 'Project Alpha', code: 'ALPHA', startDate: new Date(), active: true).save(failOnError: true)
-        def projectBeta = new Project(name: 'Project Beta', code: 'BETA', startDate: new Date() - 30, active: true).save(failOnError: true)
-        def projectGamma = new Project(name: 'Project Gamma', code: 'GAMMA', startDate: new Date() - 60, active: false).save(failOnError: true)
+            // Create test departments
+            def engineering = new Department(name: 'Engineering', description: 'Software development team').save(failOnError: true)
+            def marketing = new Department(name: 'Marketing', description: 'Marketing and sales team').save(failOnError: true)
+            def hr = new Department(name: 'Human Resources', description: 'HR and recruitment').save(failOnError: true)
 
-        // Create test employees with various field types populated
-        new Employee(
-            firstName: 'John',
-            lastName: 'Doe',
-            email: 'john.doe@example.com',
-            biography: 'Senior software engineer with 10 years of experience in Java and Groovy development.',
-            age: 35,
-            salary: new BigDecimal('85000.00'),
-            hireDate: new Date() - 365,
-            active: true,
-            status: EmployeeStatus.ACTIVE,
-            priority: 'HIGH',
-            department: engineering,
-            website: new URL('https://johndoe.dev'),
-            preferredLocale: Locale.US,
-            preferredCurrency: Currency.getInstance('USD'),
-            preferredTimezone: TimeZone.getTimeZone('America/New_York'),
-            address: new Address(street: '123 Main St', city: 'New York', postalCode: '10001', country: 'USA')
-        ).addToProjects(projectAlpha).addToProjects(projectBeta).save(failOnError: true)
+            // Create test projects
+            def projectAlpha = new Project(name: 'Project Alpha', code: 'ALPHA', startDate: new Date(), active: true).save(failOnError: true)
+            def projectBeta = new Project(name: 'Project Beta', code: 'BETA', startDate: new Date() - 30.days, active: true).save(failOnError: true)
+            def projectGamma = new Project(name: 'Project Gamma', code: 'GAMMA', startDate: new Date() - 60.days, active: false).save(failOnError: true)
 
-        new Employee(
-            firstName: 'Jane',
-            lastName: 'Smith',
-            email: 'jane.smith@example.com',
-            biography: 'Marketing specialist focused on digital campaigns.',
-            age: 28,
-            salary: new BigDecimal('65000.00'),
-            hireDate: new Date() - 180,
-            active: true,
-            status: EmployeeStatus.ACTIVE,
-            priority: 'MEDIUM',
-            department: marketing,
-            preferredLocale: Locale.UK,
-            preferredCurrency: Currency.getInstance('GBP'),
-            preferredTimezone: TimeZone.getTimeZone('Europe/London'),
-            address: new Address(street: '456 High Street', city: 'London', postalCode: 'SW1A 1AA', country: 'UK')
-        ).addToProjects(projectBeta).save(failOnError: true)
+            // Create test employees with various field types populated
+            def john = new Employee(
+                firstName: 'John',
+                lastName: 'Doe',
+                email: 'john.doe@example.com',
+                biography: 'Senior software engineer with 10 years of experience in Java and Groovy development.',
+                age: 35,
+                salary: new BigDecimal('85000.00'),
+                hireDate: new Date() - 365.days,
+                active: true,
+                status: EmployeeStatus.ACTIVE,
+                priority: 'HIGH',
+                department: engineering,
+                website: new URL('https://johndoe.dev'),
+                preferredLocale: Locale.US,
+                preferredCurrency: Currency.getInstance('USD'),
+                preferredTimezone: TimeZone.getTimeZone('America/New_York'),
+                address: new Address(street: '123 Main St', city: 'New York', postalCode: '10001', country: 'USA')
+            ).addToProjects(projectAlpha).addToProjects(projectBeta).save(failOnError: true)
 
-        new Employee(
-            firstName: 'Bob',
-            lastName: 'Wilson',
-            email: 'bob.wilson@example.com',
-            age: 45,
-            salary: new BigDecimal('95000.00'),
-            hireDate: new Date() - 730,
-            active: false,
-            status: EmployeeStatus.ON_LEAVE,
-            priority: 'LOW',
-            department: hr,
-            preferredLocale: Locale.CANADA,
-            preferredCurrency: Currency.getInstance('CAD'),
-            preferredTimezone: TimeZone.getTimeZone('America/Toronto')
-        ).save(failOnError: true)
+            new Employee(
+                firstName: 'Jane',
+                lastName: 'Smith',
+                email: 'jane.smith@example.com',
+                biography: 'Marketing specialist focused on digital campaigns.',
+                age: 28,
+                salary: new BigDecimal('65000.00'),
+                hireDate: new Date() - 180.days,
+                active: true,
+                status: EmployeeStatus.ACTIVE,
+                priority: 'MEDIUM',
+                department: marketing,
+                preferredLocale: Locale.UK,
+                preferredCurrency: Currency.getInstance('GBP'),
+                preferredTimezone: TimeZone.getTimeZone('Europe/London'),
+                address: new Address(street: '456 High Street', city: 'London', postalCode: 'SW1A 1AA', country: 'UK')
+            ).addToProjects(projectBeta).save(failOnError: true)
 
-        // Create additional employees for pagination testing
-        (1..25).each { i ->
             new Employee(
-                firstName: "Test${i}",
-                lastName: "User${i}",
-                email: "test${i}@example.com",
-                age: 20 + (i % 30),
-                salary: new BigDecimal(50000 + (i * 1000)),
-                hireDate: new Date() - (i * 10),
-                active: i % 2 == 0,
-                status: EmployeeStatus.values()[i % EmployeeStatus.values().length],
-                priority: ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'][i % 4],
-                department: [engineering, marketing, hr][i % 3]
+                firstName: 'Bob',
+                lastName: 'Wilson',
+                email: 'bob.wilson@example.com',
+                age: 45,
+                salary: new BigDecimal('95000.00'),
+                hireDate: new Date() - 730.days,
+                active: false,
+                status: EmployeeStatus.ON_LEAVE,
+                priority: 'LOW',
+                department: hr,
+                preferredLocale: Locale.CANADA,
+                preferredCurrency: Currency.getInstance('CAD'),
+                preferredTimezone: TimeZone.getTimeZone('America/Toronto')
             ).save(failOnError: true)
-        }
-    }
 
-    def destroy = {
+            // Create additional employees for pagination testing
+            (1..25).each { i ->
+                new Employee(
+                    firstName: "Test${i}",
+                    lastName: "User${i}",
+                    email: "test${i}@example.com",
+                    age: 20 + (i % 30),
+                    salary: new BigDecimal(50000 + (i * 1000)),
+                    hireDate: new Date() - (i * 10).days,
+                    active: i % 2 == 0,
+                    status: EmployeeStatus.values()[i % EmployeeStatus.values().length],
+                    priority: ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'][i % 4],
+                    department: [engineering, marketing, hr][i % 3]
+                ).save(failOnError: true)
+            }
+        }
     }
 }
diff --git a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/CustomTemplatesSpec.groovy b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/CustomTemplatesSpec.groovy
index ae6a41cdd6..5a6b398866 100644
--- a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/CustomTemplatesSpec.groovy
+++ b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/CustomTemplatesSpec.groovy
@@ -82,13 +82,13 @@ class CustomTemplatesSpec extends ContainerGebSpec {
 
     def "custom email template shows validation error with custom styling"() {
         given: "navigating to employee create page"
-        to EmployeeCreatePage
+        def page = to EmployeeCreatePage
 
         when: "submitting with invalid email"
-        firstNameField.value('John')
-        lastNameField.value('Doe')
-        emailField.value('invalid-email')
-        createButton.click()
+        page.firstNameField.value('John')
+        page.lastNameField.value('Doe')
+        page.emailField.value('invalid-email')
+        page.createButton.click()
 
         then: "custom validation error styling is shown or we stay on form"
         waitFor {
@@ -104,18 +104,18 @@ class CustomTemplatesSpec extends ContainerGebSpec {
 
     def "custom biography template shows errors with custom styling"() {
         given: "navigating to employee create page"
-        to EmployeeCreatePage
+        def page = to EmployeeCreatePage
 
         and: "fill in required fields"
-        firstNameField.value('Jane')
-        lastNameField.value('Smith')
-        emailField.value('jane@example.com')
+        page.firstNameField.value('Jane')
+        page.lastNameField.value('Smith')
+        page.emailField.value('jane@example.com')
 
         when: "entering very long biography exceeding constraints"
         // The biography field has maxSize: 5000 constraint
         // We need to trigger a validation error another way since textarea doesn't enforce easily
         // Instead, test that the custom wrapper renders correctly
-        createButton.click()
+        page.createButton.click()
 
         then: "form is submitted (biography is nullable so no error expected)"
         // This verifies the template is functional during form submission
diff --git a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/FieldTypesSpec.groovy b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/FieldTypesSpec.groovy
index 21f553bf63..cdff3a66ec 100644
--- a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/FieldTypesSpec.groovy
+++ b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/FieldTypesSpec.groovy
@@ -241,10 +241,10 @@ class FieldTypesSpec extends ContainerGebSpec {
         $(selector).displayed || true // Graceful if field is optional
 
         where:
-        fieldName           | selector
-        'firstName'         | 'input[name="firstName"]'
-        'lastName'          | 'input[name="lastName"]'
-        'email'             | 'input[name="email"]'
-        'active'            | 'input[name="active"]'
+        fieldName   | selector
+        'firstName' | 'input[name="firstName"]'
+        'lastName'  | 'input[name="lastName"]'
+        'email'     | 'input[name="email"]'
+        'active'    | 'input[name="active"]'
     }
 }
diff --git a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/PaginationSpec.groovy b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/PaginationSpec.groovy
index 6efc30c11e..e7fb0d9121 100644
--- a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/PaginationSpec.groovy
+++ b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/PaginationSpec.groovy
@@ -16,15 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package scaffoldingfields
 
-import grails.plugin.geb.ContainerGebSpec
-import grails.testing.mixin.integration.Integration
-import scaffoldingfields.pages.EmployeeListPage
 import scaffoldingfields.pages.DepartmentListPage
+import scaffoldingfields.pages.EmployeeListPage
 import spock.lang.Stepwise
 
+import grails.plugin.geb.ContainerGebSpec
+import grails.testing.mixin.integration.Integration
+
 /**
  * Functional tests for scaffolded list pagination and sorting.
  * 
@@ -35,26 +35,23 @@ import spock.lang.Stepwise
  * 4. Sort state is preserved across page navigation
  * 5. Item count and page info are displayed correctly
  */
-@Integration
 @Stepwise
+@Integration
 class PaginationSpec extends ContainerGebSpec {
 
-    def setupSpec() {
-        // Bootstrap data should create enough records for pagination
-    }
-
+    // TODO: Not fully implemented
     def "employee list displays pagination when records exceed page size"() {
         when: "navigating to employee list"
-        to EmployeeListPage
+        def page = to EmployeeListPage
 
         then: "list page is displayed"
         at EmployeeListPage
 
         and: "table with data is shown"
-        dataTable.displayed
+        page.dataTable.displayed
 
         and: "rows are present"
-        tableRows.size() > 0
+        page.tableRows.size() > 0
     }
 
     def "employee list shows sortable column headers"() {
@@ -67,54 +64,46 @@ class PaginationSpec extends ContainerGebSpec {
         $('th', text: contains('First')).displayed
     }
 
+    // TODO: Not fully implemented
     def "clicking column header sorts ascending"() {
         given: "on employee list page"
-        to EmployeeListPage
+        def page = to EmployeeListPage
 
         when: "clicking on a sortable column header"
-        def sortLink = $('th a').find { it.text()?.toLowerCase()?.contains('first') || it.text()?.toLowerCase()?.contains('last') }
-        if (sortLink) {
-            sortLink.click()
-            waitFor { currentUrl.contains('sort=') || tableRows.size() > 0 }
-        }
+        page.sortLink('First Name').click()
 
         then: "page reloads with sorted data"
         at EmployeeListPage
-        tableRows.size() > 0
+        currentUrl.contains('sort=')
+        page.tableRows.size() > 0
     }
 
+    // TODO: Not fully implemented
     def "clicking same column header again sorts descending"() {
         given: "on employee list page with ascending sort"
-        to EmployeeListPage
-        def sortLink = $('th a').find { it.text()?.toLowerCase()?.contains('first') || it.text()?.toLowerCase()?.contains('last') }
-        if (sortLink) {
-            sortLink.click()
-            waitFor { tableRows.size() > 0 }
-        }
+        def page = to EmployeeListPage
+        page.sortLink('First Name').click()
 
         when: "clicking the same column header again"
-        sortLink = $('th a').find { it.text()?.toLowerCase()?.contains('first') || it.text()?.toLowerCase()?.contains('last') }
-        if (sortLink) {
-            sortLink.click()
-            waitFor { tableRows.size() > 0 }
-        }
+        page.sortLink('First Name').click()
 
         then: "sort order changes"
         at EmployeeListPage
-        tableRows.size() > 0
+        page.tableRows.size() > 0
     }
 
+    // TODO: Not fully implemented
     def "pagination links navigate between pages"() {
         given: "on employee list page"
-        to EmployeeListPage
-        def initialRowCount = tableRows.size()
+        def page = to EmployeeListPage
+        //def initialRowCount = page.tableRows.size()
 
         when: "checking for pagination controls"
         def nextLink = $('a.step', text: contains('Next')) ?: $('a', text: contains('Next')) ?: $('a.nextLink')
         def paginationExists = nextLink?.displayed ?: $('nav.pagination').displayed ?: $('ul.pagination').displayed
 
         then: "list is displayed"
-        tableRows.size() > 0
+        page.tableRows.size() > 0
 
         // Pagination may or may not be present depending on data volume
         // If pagination exists, we test it; otherwise we just verify the list works
@@ -122,37 +111,41 @@ class PaginationSpec extends ContainerGebSpec {
 
     def "department list displays records"() {
         when: "navigating to department list"
-        to DepartmentListPage
+        def page = to DepartmentListPage
 
         then: "list page is displayed"
         at DepartmentListPage
 
         and: "table with data is shown"
-        dataTable.displayed
+        page.dataTable.displayed
 
         and: "rows are present from bootstrap data"
-        tableRows.size() > 0
+        page.tableRows.size() > 0
     }
 
     def "department list shows department names"() {
         when: "navigating to department list"
-        to DepartmentListPage
+        def page = to DepartmentListPage
 
         then: "department names are visible"
-        tableRows.find { it.text()?.contains('Engineering') || it.text()?.contains('Marketing') || it.text()?.contains('Sales') }
+        page.tableRows.find {
+            it.text()?.contains('Engineering') || it.text()?.contains('Marketing') || it.text()?.contains('Sales')
+        }
     }
 
+    // TODO: Not fully implemented
     def "list shows correct record count information"() {
         when: "navigating to employee list"
-        to EmployeeListPage
+        def page = to EmployeeListPage
 
         then: "page displays records"
-        tableRows.size() > 0
+        page.tableRows.size() > 0
 
         // Record count info may be displayed in various formats
         // Just verify the page is functional
     }
 
+    // TODO: Not fully implemented
     def "empty search results show appropriate message"() {
         when: "navigating to employee list with filter that matches nothing"
         go '/employee/index?firstName=NONEXISTENT_12345'
@@ -163,45 +156,48 @@ class PaginationSpec extends ContainerGebSpec {
         // Either shows empty table or no results message
     }
 
+    // TODO: Not fully implemented
     def "list maintains state across browser refresh"() {
         given: "on sorted employee list"
-        to EmployeeListPage
+        def page = to EmployeeListPage
 
         when: "sorting by a column"
         def sortLink = $('th a').first()
         if (sortLink?.displayed) {
             sortLink.click()
-            waitFor { tableRows.size() > 0 }
+            waitFor { page.tableRows.size() > 0 }
         }
         def currentUrlBeforeRefresh = currentUrl
 
         and: "refreshing the page"
         driver.navigate().refresh()
-        waitFor { tableRows.size() > 0 }
+        waitFor { page.tableRows.size() > 0 }
 
         then: "sort parameters are preserved in URL or list is still functional"
         at EmployeeListPage
-        tableRows.size() > 0
+        page.tableRows.size() > 0
     }
 
+    // TODO: Not fully implemented
     def "pagination works with sorting applied"() {
         given: "on employee list page"
-        to EmployeeListPage
+        def page = to EmployeeListPage
 
         when: "applying a sort"
         def sortLink = $('th a').first()
         if (sortLink?.displayed) {
             sortLink.click()
-            waitFor { tableRows.size() > 0 }
+            waitFor { page.tableRows.size() > 0 }
         }
 
         then: "sorted list is displayed"
-        tableRows.size() > 0
+        page.tableRows.size() > 0
 
         // If pagination is available with current data set, verify it works with sort
         // This ensures sort and pagination don't conflict
     }
 
+    // TODO: Not fully implemented
     def "max parameter limits displayed records"() {
         when: "navigating with max parameter"
         go '/employee/index?max=2'
@@ -212,6 +208,7 @@ class PaginationSpec extends ContainerGebSpec {
         // The max parameter should limit results (if there's data)
     }
 
+    // TODO: Not fully implemented
     def "offset parameter skips records"() {
         when: "navigating with offset parameter"
         go '/employee/index?offset=1'
@@ -222,6 +219,7 @@ class PaginationSpec extends ContainerGebSpec {
         // The offset parameter should skip initial records
     }
 
+    // TODO: Not fully implemented
     def "combined max and offset parameters work together"() {
         when: "navigating with both max and offset"
         go '/employee/index?max=5&offset=0'
diff --git a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/RelationshipsFunctionalSpec.groovy b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/RelationshipsFunctionalSpec.groovy
index 74f6537635..4f40f4fd73 100644
--- a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/RelationshipsFunctionalSpec.groovy
+++ b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/RelationshipsFunctionalSpec.groovy
@@ -16,9 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package scaffoldingfields
 
+import spock.lang.PendingFeature
+
 import grails.gorm.transactions.Rollback
 import grails.plugin.geb.ContainerGebSpec
 import grails.testing.mixin.integration.Integration
@@ -27,8 +28,8 @@ import grails.testing.mixin.integration.Integration
  * Functional tests for relationship handling in scaffolded views.
  * Tests belongsTo, hasMany, and manyToMany relationship rendering.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class RelationshipsFunctionalSpec extends ContainerGebSpec {
 
     // ==================== BELONGSTO RELATIONSHIP ====================
@@ -38,7 +39,7 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         go '/employee/create'
 
         then: "department select is present with options"
-        def deptSelect = $('select[name="department"], select[name="department.id"]')
+        def deptSelect = $('select[name="department.id"]')
         deptSelect.displayed
 
         and: "select contains departments from bootstrap"
@@ -54,11 +55,8 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         go '/employee/create'
 
         when: "selecting a department and filling required fields"
-        def deptSelect = $('select[name="department"], select[name="department.id"]')
-        if (deptSelect.displayed) {
-            // Select Engineering department
-            deptSelect.find('option', text: contains('Engineering')).click()
-        }
+        def deptSelect = $('select[name="department.id"]')
+        deptSelect.find('option', text: contains('Engineering')).click()
         $('input[name="firstName"]').value('Related')
         $('input[name="lastName"]').value('Employee')
         $('input[name="email"]').value('related.employee@example.com')
@@ -67,7 +65,8 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         $('input[type="submit"], button[type="submit"]').click()
 
         then: "employee is created successfully"
-        !title.contains('Create') || title.contains('Employee')
+        !title.contains('Create')
+        title.contains('Show Employee')
     }
 
     def "Show page displays belongsTo association"() {
@@ -76,7 +75,8 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
 
         then: "department is displayed"
         def pageContent = $('body').text()
-        pageContent.contains('Department') || pageContent.contains('Engineering') || true
+        pageContent.contains('Department')
+        pageContent.contains('Engineering')
     }
 
     def "Edit page preserves belongsTo selection"() {
@@ -85,10 +85,8 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
 
         then: "department select has a value selected"
         def deptSelect = $('select[name="department"], select[name="department.id"]')
-        if (deptSelect.displayed) {
-            def selectedOption = deptSelect.find('option:checked, option[selected]')
-            selectedOption.size() >= 0 // May or may not have selection
-        }
+        def selectedOption = deptSelect.find('option:checked, option[selected]')
+        selectedOption.text().contains('Engineering')
     }
 
     // ==================== HASMANY RELATIONSHIP (Parent Side) ====================
@@ -97,12 +95,13 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         when: "navigating to a department show page"
         go '/department/show/1'
 
-        then: "employees list may be displayed"
+        then: "employees list is displayed"
         def pageContent = $('body').text()
-        // Employees might be shown as a list
-        pageContent.contains('Employee') || pageContent.contains('John') || true
+        pageContent.contains('Employees')
+        pageContent.contains('John')
     }
 
+    // TODO: Not fully implemented
     def "Department list shows employee count or link"() {
         when: "navigating to department list"
         go '/department/index'
@@ -121,11 +120,11 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         then: "projects field may be multi-select"
         def projectsSelect = $('select[name="projects"]')
         // HasMany on create might not show or might be multi-select
-        !projectsSelect.displayed ||
-        projectsSelect.attr('multiple') != null ||
+        projectsSelect.attr('multiple') != null
         projectsSelect.find('option').size() >= 0
     }
 
+    // TODO: Not fully implemented
     def "Can select multiple hasMany items"() {
         given: "navigating to employee edit page with projects"
         go '/employee/edit/1'
@@ -134,27 +133,30 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         def projectsSelect = $('select[name="projects"]')
 
         then: "can interact with multi-select if present"
-        !projectsSelect.displayed || true // Graceful if not shown
+        projectsSelect.displayed
     }
 
     // ==================== MANYTOMANY RELATIONSHIP ====================
 
+    @PendingFeature(reason = 'Many-to-many relationship does not show up on page')
     def "Project shows many-to-many employees"() {
         when: "navigating to project show page"
         go '/project/show/1'
 
         then: "employees may be displayed"
         def pageContent = $('body').text()
-        pageContent.contains('Employee') || pageContent.contains('John') || true
+        pageContent.contains('Employees')
+        pageContent.contains('John')
     }
 
     def "Project edit allows selecting multiple employees"() {
         when: "navigating to project edit page"
         go '/project/edit/1'
 
-        then: "employees select may be present"
+        then: "employees is present"
         def employeesSelect = $('select[name="employees"]')
-        !employeesSelect.displayed || employeesSelect.find('option').size() >= 0
+        employeesSelect.displayed
+        employeesSelect.find('option').size() >= 0
     }
 
     // ==================== EMBEDDED RELATIONSHIP ====================
@@ -170,9 +172,10 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         def postalCodeField = $('input[name="address.postalCode"]')
         def countryField = $('input[name="address.country"]')
 
-        // At least some embedded fields should be present
-        streetField.displayed || cityField.displayed ||
-        postalCodeField.displayed || countryField.displayed || true
+        streetField.displayed
+        cityField.displayed
+        postalCodeField.displayed
+        countryField.displayed
     }
 
     def "Can save entity with embedded object"() {
@@ -185,34 +188,33 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         $('input[name="email"]').value('embedded.address@example.com')
 
         def streetField = $('input[name="address.street"]')
-        if (streetField.displayed) {
-            streetField.value('789 Test Street')
-        }
+        streetField.value('789 Test Street')
         def cityField = $('input[name="address.city"]')
-        if (cityField.displayed) {
-            cityField.value('Test City')
-        }
+        cityField.value('Test City')
 
         and: "submitting the form"
         $('input[type="submit"], button[type="submit"]').click()
 
         then: "entity is created"
-        !title.contains('Create') || title.contains('Employee')
+        !title.contains('Create')
+        title.contains('Employee')
     }
 
     def "Show page displays embedded object properties"() {
         when: "navigating to employee show page with address"
         go '/employee/show/1'
 
-        then: "address fields may be displayed"
+        then: "address fields are displayed"
         def pageContent = $('body').text()
         // Check for any address-related content
-        pageContent.contains('Address') || pageContent.contains('Street') ||
-        pageContent.contains('New York') || true
+        pageContent.contains('Address')
+        pageContent.contains('Street')
+        pageContent.contains('New York')
     }
 
     // ==================== RELATIONSHIP CONSISTENCY ====================
 
+    // TODO: Not fully implemented
     def "Creating employee with department updates department employee count"() {
         given: "count existing employees in engineering"
         go '/department/show/1'
@@ -221,16 +223,15 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         when: "creating new employee in engineering"
         go '/employee/create'
         def deptSelect = $('select[name="department"], select[name="department.id"]')
-        if (deptSelect.displayed) {
-            deptSelect.find('option', text: contains('Engineering')).click()
-        }
+        deptSelect.find('option', text: contains('Engineering')).click()
         $('input[name="firstName"]').value('New')
         $('input[name="lastName"]').value('EngineerTest')
         $('input[name="email"]').value('new.engineer.test@example.com')
         $('input[type="submit"], button[type="submit"]').click()
 
         then: "employee was created"
-        !title.contains('Create') || title.contains('Employee')
+        !title.contains('Create')
+        title.contains('Employee')
     }
 
     // ==================== NULL ASSOCIATION HANDLING ====================
@@ -249,7 +250,8 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         $('input[type="submit"], button[type="submit"]').click()
 
         then: "entity is created without association"
-        !title.contains('Create') || title.contains('Employee')
+        !title.contains('Create')
+        title.contains('Employee')
     }
 
     def "Show page handles null associations gracefully"() {
@@ -257,6 +259,8 @@ class RelationshipsFunctionalSpec extends ContainerGebSpec {
         go '/employee/show/3' // Bob Wilson has no projects
 
         then: "page renders without errors"
-        title.contains('Employee') || title.contains('Show') || $('body').text().contains('Wilson')
+        title.contains('Employee')
+        title.contains('Show')
+        $('body').text().contains('Wilson')
     }
 }
diff --git a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/ValidationFunctionalSpec.groovy b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/ValidationFunctionalSpec.groovy
index c44f00c366..10cbf2ed3a 100644
--- a/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/ValidationFunctionalSpec.groovy
+++ b/grails-test-examples/scaffolding-fields/src/integration-test/groovy/scaffoldingfields/ValidationFunctionalSpec.groovy
@@ -16,7 +16,6 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package scaffoldingfields
 
 import grails.gorm.transactions.Rollback
@@ -27,12 +26,13 @@ import grails.testing.mixin.integration.Integration
  * Functional tests for form validation error display.
  * Tests that validation errors are properly rendered in scaffolded views.
  */
-@Integration(applicationClass = Application)
 @Rollback
+@Integration
 class ValidationFunctionalSpec extends ContainerGebSpec {
 
     // ==================== REQUIRED FIELD VALIDATION ====================
 
+    // TODO: Not fully implemented
     def "Blank required field shows error message"() {
         given: "navigating to the employee create page"
         go '/employee/create'
@@ -52,6 +52,7 @@ class ValidationFunctionalSpec extends ContainerGebSpec {
         }
     }
 
+    // TODO: Not fully implemented
     def "Blank first name shows specific error"() {
         given: "navigating to the employee create page"
         go '/employee/create'
@@ -70,7 +71,7 @@ class ValidationFunctionalSpec extends ContainerGebSpec {
     }
 
     // ==================== EMAIL VALIDATION ====================
-
+    // TODO: Not fully implemented
     def "Invalid email format shows error message"() {
         given: "navigating to the employee create page"
         go '/employee/create'
@@ -102,16 +103,15 @@ class ValidationFunctionalSpec extends ContainerGebSpec {
 
         then: "error is shown for duplicate email - validation prevents navigation away"
         waitFor(5) {
-            title == 'Create Employee' ||
-            currentUrl.contains('/employee/create') ||
-            $('.errors, .alert-danger, .invalid-feedback').displayed ||
-            // If unique constraint not configured, may go to show page - still valid test
-            currentUrl.contains('/employee/show/')
+            title == 'Create Employee'
+            $('.alert-danger').displayed
+            pageSource.contains('Property [email] of class [class scaffoldingfields.Employee] with value [john.doe@example.com] must be unique')
         }
     }
 
     // ==================== NUMERIC VALIDATION ====================
 
+    // TODO: Not fully implemented
     def "Age below minimum shows error"() {
         given: "navigating to the employee create page"
         go '/employee/create'
@@ -121,9 +121,7 @@ class ValidationFunctionalSpec extends ContainerGebSpec {
         $('input[name="lastName"]').value('Person')
         $('input[name="email"]').value('young.person@example.com')
         def ageField = $('input[name="age"]')
-        if (ageField.displayed) {
-            ageField.value('10')
-        }
+        ageField.value('10')
         $('input[type="submit"], button[type="submit"]').click()
 
         then: "error is shown if age was provided"
@@ -131,6 +129,7 @@ class ValidationFunctionalSpec extends ContainerGebSpec {
         true
     }
 
+    // TODO: Not fully implemented
     def "Age above maximum shows error"() {
... 139 lines suppressed ...