Repository: mockito/mockito
Issue: Assertions on parameters during verification

### Suggestion
I would like to suggest adding an API allowing for assertions during parameter verification without argument captors in simple cases.

### Motivation
In my projects I generally use Mockito and AssertJ for testing. For non trivial method parameters, I often encounter the following ArgumentCaptor pattern:
```java
ClassUnderTest classUnderTest = new ClassUnderTest(otherServiceMock);

classUnderTest.method();

ArgumentCaptor<Param> paramArgumentCaptor = ArgumentCaptor.forClass(Param.class);
verify(otherServiceMock).doStuff(paramArgumentCaptor.capture());
Param paramFromCaptor = paramArgumentCaptor.getValue();
assertThat(paramFromCaptor.getField1()).isEqualTo("value1");
assertThat(paramFromCaptor.getField2()).isEqualTo("value2");
```

This is fine, but a little bit verbose.

An alternative pattern I find myself using lately is using the `argThat` argument matcher to eliminate the captor, resulting in the verify statement looking something like this:
```java
verify(otherServiceMock).doStuff(argThat(param -> {
    assertThat(param.getField1()).isEqualTo("value1");
    assertThat(param.getField2()).isEqualTo("value2");
    return true;
}));
```
In my opinion, at least in simple cases where only assertions on a single parameter are desired, this looks a little cleaner. Just the return statement is a bit pointless.

My suggestion is adding an API that would allow eliminating the return statement in this pattern, for example:

```java
verify(otherServiceMock).doStuff(assertArg(param -> {
    assertThat(param.getField1()).isEqualTo("value1");
    assertThat(param.getField2()).isEqualTo("value2");
}));
```

Or is there already an API that would allow a similar pattern that I've missed? 

Issue comments:
I also like the idea about removing this `return true` statement when I wrote something which is more "assertion" than "matching".

But it seems there is some limitation about this, see : [**`argThat` plus asserts**](https://stackoverflow.com/a/57281503/5088764).
Not sure to understand details, maybe a Mockito committer could explain this ?

Ideally, I think it would be great if **Mockito** provide an elegant way to use **AssertJ** to match arguments and/or more generally provide a way to assert arguments instead of matching it.

Waiting, you could implement your own : 
**The general way** (not dependent of AssertJ - source : https://github.com/assertj/assertj/issues/972#issuecomment-399988670)
```java
public static <T> T assertArg(Consumer<T> assertion) {
    return argThat(argument -> {
        assertion.accept(argument);
        return true;
    });
}
```
**The AssertJ oriented** (depend of AssertJ and unfortunately Hamcrest too...  - source : https://gist.github.com/superbob/091489c61ce9bd79d14a4d3d731c9c49?permalink_comment_id=3863242#gistcomment-3863242)
```java
import org.assertj.core.matcher.AssertionMatcher;
import org.mockito.hamcrest.MockitoHamcrest;

import java.util.function.Consumer;

public class TestUtil {

    public static <T> T assertArg(Consumer<T> assertions) {
        return MockitoHamcrest.argThat(new AssertionMatcher<T>() {
            @Override
            public void assertion(T actual) throws AssertionError {
                assertions.accept(actual);
            }
        });
    }
}
```
I didn't dig to understand what is the benefits of AssertJ oriented solution compare to general way ...  maybe better miss match report ? :shrug: 
if the AssertJ oriented solution is better, I guess it should be great to have one without Hamcrest dependency.

Pull request review comments:
I just realized that throwing an exception might cause stateful problems in our tracking mechanism. E.g. if we match on arguments and we throw an exception somewhere, I am not sure how Mockito recovers. Given that this PR passes the checks, I think this is fine, but let's codify this explicitly.

Can we add the following test cases?

```java
    @Test
    public void can_invoke_method_on_mock_after_assert_arg() throws Exception {
        mock.oneArg("hello");

        try {
            verify(mock).oneArg(assertArg((String it) -> assertEquals("not-hello", it)));
            fail("Should throw an exception");
        } catch (ComparisonFailure e) {
            // do nothing
        }

        mock.oneArg("hello");
    }

    @Test
    public void can_verify_on_mock_after_assert_arg() throws Exception {
        mock.oneArg("hello");

        try {
            verify(mock).oneArg(assertArg((String it) -> assertEquals("not-hello", it)));
            fail("Should throw an exception");
        } catch (ComparisonFailure e) {
            // do nothing
        }

        verify(mock).oneArg("hello");
    }
```
@TimvdLippe tests added

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/ArgumentMatchers.java b/src/main/java/org/mockito/ArgumentMatchers.java
index de87f298a1..1743ce164b 100644
--- a/src/main/java/org/mockito/ArgumentMatchers.java
+++ b/src/main/java/org/mockito/ArgumentMatchers.java
@@ -14,6 +14,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.regex.Pattern;
 
 import org.mockito.internal.matchers.Any;
@@ -912,6 +913,22 @@ public static <T> T argThat(ArgumentMatcher<T> matcher) {
         return null;
     }
 
+    /**
+     * Allows creating custom argument matchers where matching is considered successful when the consumer given by parameter does not throw an exception.
+     * <p>
+     * Typically used with {@link Mockito#verify(Object)} to execute assertions on parameters passed to the verified method invocation.
+     *
+     * @param consumer executes assertions on the verified argument
+     * @return <code>null</code>.
+     */
+    public static <T> T assertArg(Consumer<T> consumer) {
+        return argThat(
+                argument -> {
+                    consumer.accept(argument);
+                    return true;
+                });
+    }
+
     /**
      * Allows creating custom <code>char</code> argument matchers.
      * <p>
diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java
index 428655e4a8..1fce63e51e 100644
--- a/src/main/java/org/mockito/Mockito.java
+++ b/src/main/java/org/mockito/Mockito.java
@@ -39,6 +39,7 @@
 import org.mockito.verification.VerificationMode;
 import org.mockito.verification.VerificationWithTimeout;
 
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 /**
@@ -1661,6 +1662,19 @@
  * With an implicit type, the Java compiler is unable to automatically determine the type of a mock and you need
  * to pass in the {@code Class} explicitly.
  * </p>
+ *
+ * <h3 id="55">55. <a class="meaningful_link" href="#verification_with_assertions" name="verification_with_assertions">
+ *  Verification with assertions</a> (Since 5.3.0)</h3>
+ *
+ * To validate arguments during verification, instead of capturing them with {@link ArgumentCaptor}, you can now
+ * use {@link ArgumentMatchers#assertArg(Consumer)}}:
+ *
+ * <pre class="code"><code class="java">
+ *   verify(serviceMock).doStuff(assertArg(param -&gt; {
+ *     assertThat(param.getField1()).isEqualTo("foo");
+ *     assertThat(param.getField2()).isEqualTo("bar");
+ *   }));
+ * </code></pre>
  */
 @CheckReturnValue
 @SuppressWarnings("unchecked")


Test patch:
diff --git a/src/test/java/org/mockitousage/matchers/MatchersTest.java b/src/test/java/org/mockitousage/matchers/MatchersTest.java
index 777c49a063..f89b44b731 100644
--- a/src/test/java/org/mockitousage/matchers/MatchersTest.java
+++ b/src/test/java/org/mockitousage/matchers/MatchersTest.java
@@ -20,6 +20,7 @@
 import static org.mockito.AdditionalMatchers.lt;
 import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.AdditionalMatchers.or;
+import static org.mockito.ArgumentMatchers.assertArg;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
@@ -52,6 +53,7 @@
 import java.util.RandomAccess;
 import java.util.regex.Pattern;
 
+import org.junit.ComparisonFailure;
 import org.junit.Test;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mockito;
@@ -624,4 +626,51 @@ public void nullable_matcher() throws Exception {
 
         verify(mock, times(2)).oneArg(nullable(Character.class));
     }
+
+    @Test
+    public void assertArg_matcher() throws Exception {
+        mock.oneArg("hello");
+
+        verify(mock).oneArg(assertArg((String it) -> assertEquals("hello", it)));
+    }
+
+    @Test
+    public void assertArg_matcher_fails_when_assertion_fails() throws Exception {
+        mock.oneArg("hello");
+
+        try {
+            verify(mock).oneArg(assertArg((String it) -> assertEquals("not-hello", it)));
+            fail("Should throw an exception");
+        } catch (ComparisonFailure e) {
+            // do nothing
+        }
+    }
+
+    @Test
+    public void can_invoke_method_on_mock_after_assert_arg() throws Exception {
+        mock.oneArg("hello");
+
+        try {
+            verify(mock).oneArg(assertArg((String it) -> assertEquals("not-hello", it)));
+            fail("Should throw an exception");
+        } catch (ComparisonFailure e) {
+            // do nothing
+        }
+
+        mock.oneArg("hello");
+    }
+
+    @Test
+    public void can_verify_on_mock_after_assert_arg() throws Exception {
+        mock.oneArg("hello");
+
+        try {
+            verify(mock).oneArg(assertArg((String it) -> assertEquals("not-hello", it)));
+            fail("Should throw an exception");
+        } catch (ComparisonFailure e) {
+            // do nothing
+        }
+
+        verify(mock).oneArg("hello");
+    }
 }