From f7b55d1b1f52e9e017957f1e2fbe368858c70fb6 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Sat, 25 Mar 2023 20:44:06 +0100 Subject: [PATCH 1/4] Fixes #2285 : Add `ArgumentMatchers#assertArg` method. --- .../java/org/mockito/ArgumentMatchers.java | 17 +++++++++++++++ .../mockitousage/matchers/MatchersTest.java | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+) 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 argThat(ArgumentMatcher matcher) { return null; } + /** + * Allows creating custom argument matchers where matching is considered successful when the consumer given by parameter does not throw an exception. + *

+ * 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 null. + */ + public static T assertArg(Consumer consumer) { + return argThat( + argument -> { + consumer.accept(argument); + return true; + }); + } + /** * Allows creating custom char argument matchers. *

diff --git a/src/test/java/org/mockitousage/matchers/MatchersTest.java b/src/test/java/org/mockitousage/matchers/MatchersTest.java index 777c49a063..ac6c34a5d4 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,23 @@ 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 + } + } } From cbf266bff81000e4e7adafa866865cbfdb35492b Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 3 Apr 2023 08:11:37 +0200 Subject: [PATCH 2/4] Fixes #2285 : Add Javadocs --- src/main/java/org/mockito/Mockito.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java index 428655e4a8..9c8e1cbe9a 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. *

+ * + *

55. + * Verification with assertions (Since 5.3.0)

+ * + * To validate arguments during verification, instead of capturing them with {@link ArgumentCaptor}, you can now + * use {@link ArgumentMatchers#assertArg(Consumer)}}: + * + *

+ *   verify(serviceMock).doStuff(assertArg(param -> {
+ *     assertThat(param.getField1()).isEqualTo("foo");
+ *     assertThat(param.getField2()).isEqualTo("bar");
+ *   }));
+ * 
*/ @CheckReturnValue @SuppressWarnings("unchecked") From 0ecdb541a77caa289bc3ce8b074681470e80c8e8 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 5 Apr 2023 07:05:00 +0200 Subject: [PATCH 3/4] Fixes #2285 : Fix Javadocs --- src/main/java/org/mockito/Mockito.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java index 9c8e1cbe9a..1fce63e51e 100644 --- a/src/main/java/org/mockito/Mockito.java +++ b/src/main/java/org/mockito/Mockito.java @@ -1670,7 +1670,7 @@ * use {@link ArgumentMatchers#assertArg(Consumer)}}: * *

- *   verify(serviceMock).doStuff(assertArg(param -> {
+ *   verify(serviceMock).doStuff(assertArg(param -> {
  *     assertThat(param.getField1()).isEqualTo("foo");
  *     assertThat(param.getField2()).isEqualTo("bar");
  *   }));

From f9aeefef5e1c682f27fa0c378513f20c7249c2ff Mon Sep 17 00:00:00 2001
From: Maciej Walkowiak 
Date: Tue, 11 Apr 2023 06:53:03 +0200
Subject: [PATCH 4/4] Fixes #2285 : Add tests that verify mockito behavior
 after assertion

---
 .../mockitousage/matchers/MatchersTest.java   | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/src/test/java/org/mockitousage/matchers/MatchersTest.java b/src/test/java/org/mockitousage/matchers/MatchersTest.java
index ac6c34a5d4..f89b44b731 100644
--- a/src/test/java/org/mockitousage/matchers/MatchersTest.java
+++ b/src/test/java/org/mockitousage/matchers/MatchersTest.java
@@ -645,4 +645,32 @@ public void assertArg_matcher_fails_when_assertion_fails() throws Exception {
             // 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");
+    }
 }