Question

I am having a strange issue when mocking the log field of a class. Running the same test twice shows an error the second time. This is an example of code:

class AccountConfigJSON {
    static Logger log = Logger.getLogger(AccountConfigJSON.class)

    def AccountConfigJSON(String jsonString) {
        if (jsonString) {
            json = new JSONObject(jsonString)
        } else {
            log.debug("No JSON string for account config. Will not parse")
        }
    }
}

and this is the specification

class AccountConfigJSONUnitSpec extends UnitSpec {

    def loggerMock

    def setup(){
        loggerMock = Mock(org.apache.log4j.Logger)
        org.apache.log4j.Logger.metaClass.static.getLogger = { Class clazz -> loggerMock }
    }

    def 'If jsonString is null, a log is written'(){
        when:
            new AccountConfigJSON("")
        then:
            1 * loggerMock.debug("No JSON string for account config. Will not parse")
    }

    def 'If jsonString is empty, a log is written'(){
        when:
            new AccountConfigJSON("")
        then:
            1 * loggerMock.debug("No JSON string for account config. Will not parse")
    }
}

The second test fails showing

|  Too few invocations for:

1 * loggerMock.debug("No JSON string for account config. Will not parse")   (0 invocations)

but debugging the app using Idea, clearly it runs this sentence. Any idea?

Was it helpful?

Solution

Looks odd that the actual call is executed but the interaction in not recorded. You can get around with it by explicitly assigning the mocked logger to the class as below:

def setup(){
    loggerMock = Mock(org.apache.log4j.Logger) 
    AccountConfigJSON.log = loggerMock
}

From the definition of "interaction", I think the above setup is the best way to go.

Is an Interaction Just a Regular Method Invocation?

Not quite. While an interaction looks similar to a regular method invocation, it is simply a way to express which method invocations are expected to occur. A good way to think of an interaction is as a regular expression that all incoming invocations on mock objects are matched against. Depending on the circumstances, the interaction may match zero, one, or multiple invocations.

This only happens while dealing with static object properties in a class. The moment logger is defined non-static in the class under test, everything works as expected without the work around.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top