简体   繁体   中英

Mock static java methods using Mockk

We are currently working with java with kotlin project, slowly migrating the whole code to the latter.

Is it possible to mock static methods like Uri.parse() using Mockk?

How would the sample code look like?

In addition to oleksiyp answer:

Update from 2022:

You have to use unmockStatic() . Please read another answers if automatic unmocking is not working for you.

After mockk 1.8.1:

Mockk version 1.8.1 deprecated the solution below. After that version you should do:

@Before
fun mockAllUriInteractions() {
    mockkStatic(Uri::class)
    every { Uri.parse("http://test/path") } returns Uri("http", "test", "path")
}

mockkStatic will be cleared everytime it's called, so you don't need to unmock it anymore


DEPRECATED:

If you need that mocked behaviour to always be there, not only in a single test case, you can mock it using @Before and @After :

@Before
fun mockAllUriInteractions() {
    staticMockk<Uri>().mock()
    every { Uri.parse("http://test/path") } returns Uri("http", "test", "path")    //This line can also be in any @Test case
}

@After
fun unmockAllUriInteractions() {
    staticMockk<Uri>().unmock()
}

This way, if you expect more pieces of your class to use the Uri class, you may mock it in a single place, instead of polluting your code with .use everywhere.

MockK allows mocking static Java methods. The main purpose for it is mocking of Kotlin extension functions, so it is not as powerful as PowerMock, but still does it's job even for Java static methods.

The syntax would be following:

staticMockk<Uri>().use {
    every { Uri.parse("http://test/path") } returns Uri("http", "test", "path")

    assertEquals(Uri("http", "test", "path"), Uri.parse("http://test/path"))

    verify { Uri.parse("http://test/path") }  
}

More details here: http://mockk.io/#extension-functions

Beware

If you call mockkSatic() without a block, do not forget to call unmockkStatic() after the mocked method is called. The method is not unmocked automatically and you will still get the mocked value even in different test classes which do not call mockkStatic() , but use the static method.

Another option is to execute the mocked method inside a block, then it will be automatically unmocked:

mockkStatic(Uri::class) {
    every { Uri.parse("http://test/path") } returns Uri("http", "test", "path")
    val uri = Uri.parse("http://test/path")
}

Additionally to the accepted answer:

You can't create an Uri like that, you gonna have to mock the Uri instance as well. Something like:

private val mockUri = mockk<Uri>()

@Before
fun mockAllUriInteractions() {
    mockkStatic(Uri::class)
    every { Uri.parse("http://test/path") } returns mockUri
    // or just every { Uri.parse("http://test/path") } returns mockk<Uri>()
}

If we are going to mock static, like: mockkStatic(Klass::class)

then we definitely have to unmock it, like: unmockkStatic(Klass::class)

I would suggest to unmock it in the method annotated @After.

A full example would be:

class SomeTest {
  private late var viewMode: SomeViewModel

  @Before
  fun setUp() {
    viewMode = SomeViewModel()
    mockkStatic(OurClassWithStaticMethods::class)       
  }

  @After
  fun tearDown() {
    unmockkStatic(OurClassWithStaticMethods::class)
  }

  @Test
  fun `Check that static method get() in the class OurClassWithStaticMethods was called`() {
    //Given
    every { OurClassWithStaticMethods.get<Any>(any()) } returns "dummyString"

    //When
    viewModel.doSomethingWhereStaticMethodIsCalled()

    //Then
    verify(exactly = 1) { 
       OurClassWithStaticMethods.get<Any>(any()) 
    }
  }
}

This example is written with the mocking library " Mockk " v.1.12.0

As mentioned in multiple answers above, you'll have to ensure to invoke the unmockkStatic - otherwise you'll end up with flaky tests (since the mocked object/function will be available across test classes.

In my scenario - I had a module-wide extension function in kotlin and to mock that I used a companion object like below:

class SampleTest {

companion object {
    @BeforeAll
    @JvmStatic
    fun setup() {
        mockkStatic("packagename.filenameKt")
    }

    @AfterAll
    @JvmStatic
    fun teardown() {
        unmockkStatic("packagename.filenameKt")
    }
}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM