Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support arguments capture for verify blocks #65

Open
0xnm opened this issue Dec 4, 2024 · 5 comments
Open

Support arguments capture for verify blocks #65

0xnm opened this issue Dec 4, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@0xnm
Copy link

0xnm commented Dec 4, 2024

It seems that capture is not supported for verify blocks.

Suppose we have the following:

interface Foobar {
    fun foo(bar: String)
}

And then we mock/verify it in the test:

val mockFoobar = mock<Foobar>()

mockFoobar.foo("bar")

verify {
    val container = mutableListOf<String>()
    mockFoobar.foo(capture(container))

    assertTrue(container.isNotEmpty())
}

This assertion will fail, because nothing was actually captured and container is empty.

Am I missing some additional setup or mock arguments capture is indeed not yet supported in verify blocks?

@lupuuss
Copy link
Owner

lupuuss commented Dec 5, 2024

Hi! Just like in MockK, using capture inside a verify block doesn’t produce any results. This is because capture is more like a callback: it only records arguments when the associated answer is actually invoked.

What’s your specific use case? Could simply using capture within an every block address your needs?

@0xnm
Copy link
Author

0xnm commented Dec 6, 2024

Thanks for looking at this!

The use-case is to just extract the argument for the more further assertion. Like speaking about the example above, it could be:

val value = container.first()
assertThat(value).isXXX()
...

Of course it is possible to use matching:

verify {
  mockFoobar.foo(bar = matching {
       assertThat(it).isXXX()
       true
  }
}

But coming with the Mockito Kotlin usage background, where captors can be used in the verify block:

val captor = argumentCaptor<String>()
verify(mockFoobar).foo(bar = captor.capture())

It was a bit confusing to see here that captor can be technically invoked in the verify block, but nothing is actually captured (maybe it is worth then to log some warning or make a mention in the docs?).

@lupuuss
Copy link
Owner

lupuuss commented Dec 6, 2024

How does it work with the Mockito?? Does it push all the arguments that were recorded for matching call all at once??

fooBar.call(1)
fooBar.call(2)
verify {
    val list = mutableListOf<Int>()
    fooBar.call(capture(list))
    println(list) // prints [1, 2]
}

@0xnm
Copy link
Author

0xnm commented Dec 6, 2024

Yes. This would be the following snippet:

val foobar = mock<Foobar>()
foobar.foo("a")
foobar.foo("b")

val captor = argumentCaptor<String>()
verify(foobar, times(2)).foo(captor.capture())

println(captor.allValues) // prints [a, b]

@lupuuss
Copy link
Owner

lupuuss commented Dec 8, 2024

At first glance, it seems possible to implement. I'll investigate further. If possible, I'll include it in version 2.7.0.

@lupuuss lupuuss added the enhancement New feature or request label Dec 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants