Search code examples
spring-bootgroovyspock

Spock Testing: Too few invocation


I am writing Spock test for a Service class whose method calls another method in a Dao class in a spring boot application. However, I am getting:

 Too few invocations for:
 1 * dao.getAddressFromSomewhere("me")   (0 invocations)
 Unmatched invocations (ordered by similarity):
 None

Below is the source code and the testing code, can someone please let me know what I did wrong? It seems that the dao mock didn't get invoked and return "USA" at all. I have done some research online and can't find what I did wrong.

@Service
public class ServiceClass 
{
    @Autowired
    private DaoClass dao;

    public String getAddress(String name) {         
        return dao.getAddressFromSomewhere(name);
    }
}

@Component
public class DaoClass {
     public String getAddressFromSomewhere(String name) {
     // get address from DB
     ......
     }
}

And here is my Spock testing code:

@ContextConfiguration
@Import(ServiceClass.class)
public class Test extends Specification {

@Autowired
private DaoClass dao;
@Autowired
private ServiceClass service;

@TestConfiguration
static class MockConfig {
    def detachedMockFactory = new DetachedMockFactory()
    @Bean
    DaoClass dao() {
        return detachedMockFactory.Mock(DaoClass)
    }
}

def "Test Success Senario"() {                     
    given: "dao"
          dao.getAddressFromSomewhere("me") >> "USA";

    when: "call service "
       def actualResponse = service.getAddress("me");

    then: "dao should be invoked with given response"
       1 * dao.getAddressFromSomewhere("me")
       actualResponse == "USA"
 }
}

Solution

  • By writing 1 * dao.getAddressFromSomewhere("me") in then: block you just override the interaction dao.getAddressFromSomewhere("me") >> "USA" in your given: block. And by not declaring the returning value through >> you just tell the mock to return null. You can check the interactions order with the Spock doc:

    ...Interactions declared in a then: block are matched against before any other interactions. This allows to override interactions declared in, say, a setup method with interactions declared in a then: block.

    You can rewrite your example in a couple of ways:

    1. Declare your interaction in given: block
    def "Test Success Senario"() {
        given: "dao"
        1 * dao.getAddressFromSomewhere("me") >> "USA"
    
        when: "call service "
        def actualResponse = service.getAddress("me")
    
        then: "dao should be invoked with given response"
        actualResponse == "USA"
    }
    
    1. Declare your interaction in then: block:
    def "Test Success Senario"() {
        when: "call service "
        def actualResponse = service.getAddress("me")
    
        then: "dao should be invoked with given response"
        1 * dao.getAddressFromSomewhere("me") >> "USA"
        actualResponse == "USA"
    }