Mock singleton objects and static methods

Mocking objects

When you need a singleton in Kotlin, you can use an object. These specialized classes will only ever have one instance, so you can’t mock them in the usual manner. Instead, MockK provides specialized functions to create object mocks.

  1. object FeatureFlags {
  2. val featureEnabled = true
  3. }
  4. mockkObject(FeatureFlags)
  5. every { FeatureFlags.featureEnabled } returns false
  6. // prints false
  7. println(FeatureFlags.featureEnabled)

Despite the name, object mocks behave more like spies. If a method is not stubbed, then the real method will be called. This differs from regular mocks, where a method will either throw or do nothing if it is not stubbed.

  1. class Calculator1 {
  2. fun add(a: Int, b: Int) {
  3. return a + b
  4. }
  5. }
  6. object Calculator2 {
  7. fun add(a: Int, b: Int) {
  8. return a + b
  9. }
  10. }
  11. val calculator1 = mockk<Calculator1>()
  12. mockkObject(Calculator2)
  13. // throws because the method was not stubbed
  14. println(calculator1.add(2, 2))
  15. // returns the result from the real method
  16. println(Calculator2.add(2, 2))

This approach works with any Kotlin object, which includes companion objects and enum class elements.

Mocking static methods

Sometimes you may end up working with Java code in your tests, which can have static methods.

  1. package com.name.app;
  2. class Writer {
  3. public static File getFile(String path) {
  4. return File(path);
  5. }
  6. }

Just like singleton objects, there will only ever be one version of static methods, so you cannot mock them in the usual manner. Again, MockK provides specialized functions to mock static methods.

  1. mockkStatic("com.name.app.Writer")

Rather than passing a reference to the class, you pass the class name as a string. You can also choose to pass in a reference to the class, and MockK will figure out the class name.

  1. mockkStatic(Writer::class)

Like object mocks, static mocks behave like spies. The real method will be called if the method is not stubbed.

Unmocking

If you’d like to revert back to the real object, you can use the unmockkObject method. This removes any stubbed behaviour you may have added.

  1. object Calculator {
  2. fun add(a: Int, b: Int) {
  3. return a + b
  4. }
  5. }
  6. mockkObject(Calculator)
  7. every { Calculator.add(any(), any()) } returns 10
  8. // prints 10
  9. println(Calculator.add(2, 2))
  10. unmockkObject(Calculator)
  11. // prints 4
  12. println(Calculator.add(2, 2))