Skip to main content

Debugging

Mokkery provides tools to simplify debugging in your tests.

Mock state​

You can print the state of a mock using printMokkeryDebug:

val mock = mock<Foo>()
// ...
printMokkeryDebug(mock)

This produces a JSON-like structure printed with println:

mock {
id = your.package.Foo(1)
mode = strict
answers {
getAt(index = any()) returns -1
getAt(index = 1) returns 2
getAt(index = 2) returns 4
getAt(index = 3) returns 6
}
calls {
getAt(index = 0)
getAt(index = 1)
getAt(index = 2)
}
}

You can also create this debug string manually using mokkeryDebugString and process it as needed.

Logging calls​

To log each call to a mock, register MokkeryCallLogger in call hooks.

Globally​

For quick debugging, you can simply use:

MokkeryScope.global.callHooks.beforeAnswering.register(MokkeryCallLogger())

Specific mock​

It's possible to register the logger just for a specific mock:

MokkeryScope.from(mock).callHooks.beforeAnswering.register(MokkeryCallLogger())

// or on init

mock<Foo> {
callHooks.beforeAnswering.register(MokkeryCallLogger())
}

Factory​

It is possible to register the logger for mock and spy factories. The logger is then applied to every instance created by a given factory:

val factory = mockFactoryOf(Foo::class, Bar::class) {
callHooks.beforeAnswering.register(MokkeryCallLogger())
}

Test class​

To log calls only for the duration of a single test class, register the logger before each test and unregister it after:

private val logger = MokkeryCallLogger()

@BeforeTest
fun before() {
MokkeryScope.global.callHooks.beforeAnswering.register(logger)
}

@AfterTest
fun after() {
MokkeryScope.global.callHooks.beforeAnswering.unregister(logger)
}

Module​

To register the logger once for a whole module, use a top-level function annotated with @MokkeryModuleInit. Mokkery calls it once, when Mokkery is first used in the module (e.g. a mock is created):

@MokkeryModuleInit
fun init(scope: MokkeryScope) {
scope.callHooks.beforeAnswering.register(MokkeryCallLogger())
}

The logger registered on scope applies only to mocks created in this module, so mocks created in other modules (e.g. shared test utilities) are not affected. It's also possible to register the logger in MokkeryScope.global from an initializer, so it applies to mocks from all modules:

@MokkeryModuleInit
fun init() {
MokkeryScope.global.callHooks.beforeAnswering.register(MokkeryCallLogger())
}

However, the logger is registered only when the initializer runs. For this to work correctly, the first Mokkery call in your tests must come from the module that declares the initializer. Otherwise, calls made before that, e.g. on mocks created by shared test utilities, are not logged.