mockito-kotlin icon indicating copy to clipboard operation
mockito-kotlin copied to clipboard

Support for AdditionalAnswers equivalent functions in OngoingStubbing.kt

Open sumitbhagwani opened this issue 6 years ago • 2 comments
trafficstars

Very common case when writing Mockito doAnswer is to return a value based on the input parameters.

I've added the following infix function many times in code (and its multiple arguments variants - 1 to 7 cover most cases I've ever touched)

/**
 * Sets a generic Answer for a unary function from a lambda.
 * Examples:
 * <pre>
 *   whenever(foo.hash(any())) doAnswer String::hashCode
 *   whenever(bar.addPunctuation(any())) doAnswer { s: String -> s + "!" }
 * </pre>
 */
@JvmName("doAnswer1")
infix fun <T, R> OngoingStubbing<R>.doAnswer(f: (T) -> R): OngoingStubbing<R> {
  return thenAnswer({ inv -> f(inv.arguments[0] as T) })
}

I was trying to create a PR to submit this upstream (along the lines of this commit) but I realized that it breaks the basic case when it can't decide which lambda to apply :

whenever(mocky.someFunc0()) doAnswer { 10 }

On one side, we should probably used doReturn 10 but on other side, both of them are functionally equivalent so should be allowed.

I can avoid this problem by changing the function name but it didn't felt right :-) Please let me know what is the best way for this to exist in mockito-kotlin lib. Thanks.

sumitbhagwani avatar May 08 '19 20:05 sumitbhagwani

Interesting! This indeed breaks the 'no arguments' case though, and I'm not sure yet how I feel about using a different name to overcome this.

nhaarman avatar Jul 05 '19 13:07 nhaarman

I eventually submitted it internally with doTypeAnswer for the lack of better name. I would be happy to send a PR upstream for it.

/**
 * Sets a generic Answer for a unary function from a lambda.
 * Examples:
 * <pre>
 *   whenever(foo.hash(any())) doTypedAnswer String::hashCode
 *   whenever(bar.addPunctuation(any())) doTypedAnswer { s: String -> s + "!" }
 * </pre>
 */
@JvmName("doTypedAnswer1")
infix fun <T, R> OngoingStubbing<R>.doTypedAnswer(f: (T) -> R): OngoingStubbing<R> {
  return thenAnswer({ inv -> f(inv.arguments[0] as T) })
}

sumitbhagwani avatar Jul 05 '19 16:07 sumitbhagwani