Repository: MarkusAmshove/Kluent
Pull request #174 (2020-01-16 06:58:53)

Implement VerificationMode times #49
**Description**
This PR adds the verification mode `times()` for mock verification described in this issue https://github.com/MarkusAmshove/Kluent/issues/49:
`Verify times 2 on mock that mock.getPerson(1) was called`

, we can also add a wide scope verification mode:
`Verify mode times(2) on mock that mock.getPerson(1) was called`

P.s: I know it doesn't have the best syntax but performance-wise it's the best approach, alternatively we can try to curry the `verify` method but it creates a lot of overhead.

**Checklist**
<!--- We'd like to thank you for your help, appreciate them and give you credit for it. Please check the checkboxes below as you complete them -->
- [x] I've added my name to the `AUTHORS` file, if it wasn't already present.



MarkusAmshove: Hi, I would be willing to merge this PR, since I'm okay with your provided syntax :-)

Just some thoughts as I'm not able to have a try myself currently:

```
Verify(5.times) on ...
Verify 5.times on ...
```

but I'm not sure if those are possible, not too hard to implement or discoverable enough for the user.

Let me know if you want me to merge it :)
Tenkei: Hi @MarkusAmshove regarding your suggestion, I believe that `Verify(5.times)` kind of break the convention being a function, let's say it's not Kluent ;p
As for `Verify 5.times on` sadly it's not possible. Essentially we want to capture an argument - an `int` - so we need an `infix` function. So to add this feature we have to add at least 2 segments.
Tenkei: So to wrap it up, let me know if you want to add these extra features:
**1-** Verification mode:
`Verify mode times(2) on mock that mock.getPerson(1) was called`
**1.2-** Extension function for times verification mode
`Verify mode 2.times on mock that mock.getPerson(1) was called`
**2-** Specific keyword for verifying via a verification mode
`VerifyMultipleCalls times 2 on mock that mock.getPerson(1) was called`
or
`VerifyVia mode 2.times on mock that mock.getPerson(1) was called`

Patch:
diff --git a/AUTHORS.md b/AUTHORS.md
index 1ad86e4..c04cdb8 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -38,3 +38,4 @@
 1. Ivan Mikhnovich - [@Murtaught](https://github.com/Murtaught) ([Contributions](https://github.com/MarkusAmshove/Kluent/commits?author=Murtaught))
 1. Jc Miñarro - [@JcMinarro](https://github.com/JcMinarro) ([Contributions](https://github.com/MarkusAmshove/Kluent/commits?author=JcMinarro))
 1. Kshitij Patil [@Kshitij09](https://github.com/Kshitij09) ([Contributions](https://github.com/MarkusAmshove/Kluent/commits?author=Kshitij09))
+1. Keivan Esbati - [@Tenkei](https://github.com/Tenkei) ([Contributions](https://github.com/MarkusAmshove/Kluent/commits?author=Tenkei))
diff --git a/jvm/src/main/kotlin/org/amshove/kluent/Mocking.kt b/jvm/src/main/kotlin/org/amshove/kluent/Mocking.kt
index 68ba6e3..bc230c9 100644
--- a/jvm/src/main/kotlin/org/amshove/kluent/Mocking.kt
+++ b/jvm/src/main/kotlin/org/amshove/kluent/Mocking.kt
@@ -1,9 +1,6 @@
 package org.amshove.kluent
 
-import com.nhaarman.mockitokotlin2.never
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
-import com.nhaarman.mockitokotlin2.verifyZeroInteractions
+import com.nhaarman.mockitokotlin2.*
 import org.mockito.AdditionalAnswers.*
 import org.mockito.Mockito.`when`
 import org.mockito.internal.util.MockUtil
@@ -12,11 +9,17 @@ import org.mockito.stubbing.Answer
 import org.mockito.stubbing.OngoingStubbing
 import kotlin.reflect.KClass
 
+
+
 @Suppress("UNUSED_PARAMETER") // Backward compatibility
 inline fun <reified T : Any> mock(targetClass: KClass<out T>): T = mock()
 
 inline fun <reified T : Any> mock(): T = com.nhaarman.mockitokotlin2.mock()
 
+infix fun VerifyKeyword.times(numInvocations: Int) = OngoingVerification(numInvocations)
+
+infix fun <T> OngoingVerification.on(mock: T) = verify(mock, times(numInvocations))
+
 infix fun <T> VerifyKeyword.on(mock: T) = verify(mock)
 
 infix fun <T> VerifyNotCalledKeyword.on(mock: T) = verify(mock, never())
@@ -87,3 +90,5 @@ class CalledKeyword internal constructor()
 class WhenKeyword internal constructor()
 class VerifyNoInteractionsKeyword internal constructor()
 class VerifyNoFurtherInteractionsKeyword internal constructor()
+
+class OngoingVerification(val numInvocations: Int)
\ No newline at end of file


Test patch:
diff --git a/jvm/src/test/kotlin/org/amshove/kluent/tests/mocking/VerifyCalledOnceShould.kt b/jvm/src/test/kotlin/org/amshove/kluent/tests/mocking/VerifyCalledOnceShould.kt
new file mode 100644
index 0000000..407089c
--- /dev/null
+++ b/jvm/src/test/kotlin/org/amshove/kluent/tests/mocking/VerifyCalledOnceShould.kt
@@ -0,0 +1,45 @@
+package org.amshove.kluent.tests.mocking
+
+import org.amshove.kluent.*
+import org.amshove.kluent.tests.helpclasses.Database
+import kotlin.test.Test
+import kotlin.test.assertFails
+
+class VerifyUsingTimesShould {
+
+    @Test
+    fun passWhenAMethodWasCalledSpecifiedTimes() {
+        val mock = mock(Database::class)
+        mock.getPerson(1)
+        mock.getPerson(5)
+        Verify on mock that mock.getPerson(1) was called
+        Verify on mock that mock.getPerson(5) was called
+        Verify times 2 on mock that mock.getPerson(any()) was called
+    }
+
+    @Test
+    fun failWhenAMethodWasNotCalled() {
+        val mock = mock(Database::class)
+        mock.getPerson(1)
+        Verify on mock that mock.getPerson(1) was called
+        assertFails { Verify times 1 on mock that mock.getPerson(5) was called }
+    }
+
+    @Test
+    fun failWhenAMethodWasCalledLessThanSpecified() {
+        val mock = mock(Database::class)
+        mock.getPerson(1)
+        Verify on mock that mock.getPerson(1) was called
+        assertFails { Verify times 2 on mock that mock.getPerson(any()) was called }
+    }
+
+    @Test
+    fun failWhenAMethodWasCalledMoreThanSpecified() {
+        val mock = mock(Database::class)
+        mock.getPerson(1)
+        mock.getPerson(5)
+        Verify on mock that mock.getPerson(1) was called
+        Verify on mock that mock.getPerson(5) was called
+        assertFails { Verify times 1 on mock that mock.getPerson(any()) was called }
+    }
+}
\ No newline at end of file