Grails unit test mock service vs assign service instance

179 Views Asked by At

What is the difference between mocking service and assign instance of class to service?

For example:

class MyService {

   def CallServiceMethod(){
     my business logic
   }
}

class MyController {
   def myService

   def callServiceMethod(){
     myService.callServiceMethod()
   }
}


@TestFor(MyController)
class MyControllerTests {

    @Before
    void setup() {
         controller?.myService = new MyService()
                    vs
         controller?.myService = mockFor(MyService)
    }

    void testCallServiceMethod(){
         controller.callServiceMethod()
    }
}

Any one help me please?

1

There are 1 best solutions below

0
On

When using Spring, you typically lose a lot of behavior if you create a new instance of a class that's registered as a Spring bean. Beans often have multiple other beans dependency-injected into them and those fields would be null in a plain new instance, and various annotations trigger wrapping the bean instance in one or more proxies that add extra checks and behavior before and/or after your methods are called - and that won't happen with a new instance. These proxies include the transactional wrapper you get with @Transactional, the cache checks from @Cacheable, and security checks from @Secured and other Spring Security annotations.

In addition, Grails adds a lot of code to most artifacts (in particular domain classes and controllers). Most of that is added to the bytecode, but some is added at runtime to the metaclass. Although the bytecode is there for a new instance, it often needs a final bit of configuration at runtime. For example there are over 100 GORM methods added to domain classes, but they don't work by themselves and need to be "hooked up" to the current GORM implementation (Hibernate, MongoDB, etc.) This is why you sometimes see an error like "this class was used outside of a Grails application" - the class for some reason didn't have a GORM impl attached, so it can't function.

mockFor and annotations like @TestFor and @Mock don't add all of this behavior, but they do add a large subset of it, and they add mocked but realistic implementations of many methods. The goal is to give the collaborators of your class under test enough run-app-like behavior that they work essentially like they would in a real app, so you can focus on the class being tested without having to think about configuring a test database, or fake web requests and responses, etc.