From 0a5bf8d5aac46d24d2bdc1e10595e507ece3ddbc Mon Sep 17 00:00:00 2001 From: Stefano Cordio Date: Fri, 31 Dec 2021 09:00:41 +0100 Subject: [PATCH] Add `doesNotReturn` to `Object` assertions (#2453) --- .../core/api/AbstractObjectAssert.java | 29 +++++++++- .../java/org/assertj/core/api/Assertions.java | 5 +- .../org/assertj/core/api/BDDAssertions.java | 5 +- .../org/assertj/core/api/WithAssertions.java | 5 +- .../ObjectAssert_doesNotReturn_Test.java | 56 +++++++++++++++++++ .../api/object/ObjectAssert_returns_Test.java | 22 ++++---- 6 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java diff --git a/src/main/java/org/assertj/core/api/AbstractObjectAssert.java b/src/main/java/org/assertj/core/api/AbstractObjectAssert.java index dbfa5f26f4..96c75e8135 100644 --- a/src/main/java/org/assertj/core/api/AbstractObjectAssert.java +++ b/src/main/java/org/assertj/core/api/AbstractObjectAssert.java @@ -654,7 +654,8 @@ public SELF hasFieldOrProperty(String name) { *

* Private fields are matched by default but this can be changed by calling {@link Assertions#setAllowExtractingPrivateFields(boolean) Assertions.setAllowExtractingPrivateFields(false)}. *

- * If you are looking to chain multiple assertions on different properties in a type safe way, consider chaining {@link #returns(Object, Function)} calls. + * If you are looking to chain multiple assertions on different properties in a type safe way, consider chaining + * {@link #returns(Object, Function)} and {@link #doesNotReturn(Object, Function)} calls. *

* Example: *

 public class TolkienCharacter {
@@ -1093,6 +1094,32 @@ public  SELF returns(T expected, Function from) {
     return myself;
   }
 
+  /**
+   * Verifies that the object under test does not return the given expected value from the given {@link Function},
+   * a typical usage is to pass a method reference to assert object's property.
+   * 

+ * Wrapping the given {@link Function} with {@link Assertions#from(Function)} makes the assertion more readable. + *

+ * Example: + *

 // from is not mandatory but it makes the assertions more readable
+   * assertThat(frodo).doesNotReturn("Bilbo", from(TolkienCharacter::getName))
+   *                  .doesNotReturn("Bilbo", TolkienCharacter::getName) // no from :(
+   *                  .doesNotReturn(null, from(TolkienCharacter::getRace));
+ * + * @param expected the value the object under test method's call should not return. + * @param from {@link Function} used to acquire the value to test from the object under test. Must not be {@code null} + * @param the expected value type the given {@code method} returns. + * @return {@code this} assertion object. + * @throws NullPointerException if given {@code from} function is null + * + * @since 3.22.0 + */ + public SELF doesNotReturn(T expected, Function from) { + requireNonNull(from, "The given getter method/Function must not be null"); + objects.assertNotEqual(info, from.apply(actual), expected); + return myself; + } + /** * Enable using a recursive field by field comparison strategy when calling the chained {@link RecursiveComparisonAssert#isEqualTo(Object) isEqualTo} assertion. *

diff --git a/src/main/java/org/assertj/core/api/Assertions.java b/src/main/java/org/assertj/core/api/Assertions.java index 4176086f28..0af4724ade 100644 --- a/src/main/java/org/assertj/core/api/Assertions.java +++ b/src/main/java/org/assertj/core/api/Assertions.java @@ -2211,13 +2211,14 @@ public static TemporalUnitOffset byLessThan(long value, TemporalUnit unit) { } /** - * A syntax sugar to write fluent assertion using {@link ObjectAssert#returns(Object, Function)}. + * A syntax sugar to write fluent assertion using {@link ObjectAssert#returns(Object, Function)} and + * {@link ObjectAssert#doesNotReturn(Object, Function)}. *

* Example: *

 Jedi yoda = new Jedi("Yoda", "Green");
    * assertThat(yoda).returns("Yoda", from(Jedi::getName))
    *                 .returns(2.4, from(Jedi::getHeight))
-   *                 .returns(150, from(Jedi::getWeight)); 
+ * .doesNotReturn(null, from(Jedi::getWeight));
* * @param extractor A function to extract test subject's property * @param Type of test subject diff --git a/src/main/java/org/assertj/core/api/BDDAssertions.java b/src/main/java/org/assertj/core/api/BDDAssertions.java index 9eb2baed21..0f4dec0604 100644 --- a/src/main/java/org/assertj/core/api/BDDAssertions.java +++ b/src/main/java/org/assertj/core/api/BDDAssertions.java @@ -2601,13 +2601,14 @@ public static TemporalUnitOffset byLessThan(long value, TemporalUnit unit) { } /** - * A syntax sugar to write fluent assertion using {@link ObjectAssert#returns(Object, Function)}. + * A syntax sugar to write fluent assertion using {@link ObjectAssert#returns(Object, Function)} and + * {@link ObjectAssert#doesNotReturn(Object, Function)}. *

* Example: *

 Jedi yoda = new Jedi("Yoda", "Green");
    * assertThat(yoda).returns("Yoda", from(Jedi::getName))
    *                 .returns(2.4, from(Jedi::getHeight))
-   *                 .returns(150, from(Jedi::getWeight)); 
+ * .doesNotReturn(null, from(Jedi::getWeight)); * * @param extractor A function to extract test subject's property * @param Type of test subject diff --git a/src/main/java/org/assertj/core/api/WithAssertions.java b/src/main/java/org/assertj/core/api/WithAssertions.java index 21f994f40f..5609dce478 100644 --- a/src/main/java/org/assertj/core/api/WithAssertions.java +++ b/src/main/java/org/assertj/core/api/WithAssertions.java @@ -1772,13 +1772,14 @@ default TemporalUnitOffset byLessThan(long value, TemporalUnit unit) { } /** - * A syntax sugar to write fluent assertion using {@link ObjectAssert#returns(Object, Function)}. + * A syntax sugar to write fluent assertion using {@link ObjectAssert#returns(Object, Function)} and + * {@link ObjectAssert#doesNotReturn(Object, Function)}. *

* Example: *

 Jedi yoda = new Jedi("Yoda", "Green");
    * assertThat(yoda).returns("Yoda", from(Jedi::getName))
    *                 .returns(2.4, from(Jedi::getHeight))
-   *                 .returns(150, from(Jedi::getWeight)); 
+ * .doesNotReturn(null, from(Jedi::getWeight)); * * @param extractor A function to extract test subject's property * @param Type of test subject diff --git a/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java b/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java new file mode 100644 index 0000000000..cf1c878a4f --- /dev/null +++ b/src/test/java/org/assertj/core/api/object/ObjectAssert_doesNotReturn_Test.java @@ -0,0 +1,56 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * Copyright 2012-2021 the original author or authors. + */ +package org.assertj.core.api.object; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.assertj.core.api.Assertions.from; +import static org.assertj.core.api.BDDAssertions.then; +import static org.mockito.Mockito.verify; + +import org.assertj.core.api.ObjectAssert; +import org.assertj.core.api.ObjectAssertBaseTest; +import org.assertj.core.test.Jedi; +import org.junit.jupiter.api.Test; + +class ObjectAssert_doesNotReturn_Test extends ObjectAssertBaseTest { + + @Override + protected ObjectAssert invoke_api_method() { + return assertions.doesNotReturn("Yoda", Jedi::getName); + } + + @Override + protected void verify_internal_effects() { + verify(objects).assertNotEqual(getInfo(assertions), getActual(assertions).getName(), "Yoda"); + } + + @Test + void should_fail_with_throwing_NullPointerException_if_method_is_null() { + // WHEN + Throwable thrown = catchThrowable(() -> assertions.doesNotReturn("May the force be with you.", null)); + // THEN + then(thrown).isInstanceOf(NullPointerException.class) + .hasMessage("The given getter method/Function must not be null"); + } + + @Test + void perform_assertion_like_users() { + // GIVEN + Jedi yoda = new Jedi("Yoda", "Green"); + // WHEN/THEN + assertThat(yoda).doesNotReturn("Luke", from(Jedi::getName)) + .doesNotReturn("Luke", Jedi::getName); + } + +} diff --git a/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java b/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java index 5e78aee6bd..6775fc664e 100644 --- a/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java +++ b/src/test/java/org/assertj/core/api/object/ObjectAssert_returns_Test.java @@ -13,22 +13,17 @@ package org.assertj.core.api.object; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.catchThrowable; import static org.assertj.core.api.Assertions.from; +import static org.assertj.core.api.BDDAssertions.then; import static org.mockito.Mockito.verify; -import java.util.function.Function; - -import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.ObjectAssert; import org.assertj.core.api.ObjectAssertBaseTest; -import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.assertj.core.test.Jedi; import org.junit.jupiter.api.Test; /** - * Tests for {@link AbstractObjectAssert#returns(Object, Function)}. - * * @author Takuya "Mura-Mi" Murakami */ class ObjectAssert_returns_Test extends ObjectAssertBaseTest { @@ -45,17 +40,20 @@ protected void verify_internal_effects() { @Test void should_fail_with_throwing_NullPointerException_if_method_is_null() { - ThrowingCallable code = () -> assertions.returns("May the force be with you.", null); - assertThatThrownBy(code).isExactlyInstanceOf(NullPointerException.class) - .hasMessage("The given getter method/Function must not be null"); + // WHEN + Throwable thrown = catchThrowable(() -> assertions.returns("May the force be with you.", null)); + // THEN + then(thrown).isInstanceOf(NullPointerException.class) + .hasMessage("The given getter method/Function must not be null"); } @Test void perform_assertion_like_users() { - + // GIVEN Jedi yoda = new Jedi("Yoda", "Green"); + // WHEN/THEN assertThat(yoda).returns("Yoda", from(Jedi::getName)) .returns("Yoda", Jedi::getName); - } + }