Add AssertJ support for the Model
This commit adds AssertJ compatible assertions for the Model that is generated from an HTTP request. See gh-21178
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.test.validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.ListAssert;
|
||||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied to
|
||||
* {@link BindingResult}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
* @param <SELF> the type of assertions
|
||||
*/
|
||||
public abstract class AbstractBindingResultAssert<SELF extends AbstractBindingResultAssert<SELF>> extends AbstractAssert<SELF, BindingResult> {
|
||||
|
||||
private final Failures failures = Failures.instance();
|
||||
|
||||
private final String name;
|
||||
|
||||
protected AbstractBindingResultAssert(String name, BindingResult bindingResult, Class<?> selfType) {
|
||||
super(bindingResult, selfType);
|
||||
this.name = name;
|
||||
as("Binding result for attribute '%s", this.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the total number of errors is equal to the given one.
|
||||
* @param expected the expected number of errors
|
||||
*/
|
||||
public SELF hasErrorsCount(int expected) {
|
||||
assertThat(this.actual.getErrorCount())
|
||||
.as("check errors for attribute '%s'", this.name).isEqualTo(expected);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual binding result contains fields in error with the
|
||||
* given {@code fieldNames}.
|
||||
* @param fieldNames the names of fields that should be in error
|
||||
*/
|
||||
public SELF hasFieldErrors(String... fieldNames) {
|
||||
assertThat(fieldErrorNames()).contains(fieldNames);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual binding result contains <em>only</em> fields in
|
||||
* error with the given {@code fieldNames}, and nothing else.
|
||||
* @param fieldNames the exhaustive list of field name that should be in error
|
||||
*/
|
||||
public SELF hasOnlyFieldErrors(String... fieldNames) {
|
||||
assertThat(fieldErrorNames()).containsOnly(fieldNames);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the field with the given {@code fieldName} has an error
|
||||
* matching the given {@code errorCode}.
|
||||
* @param fieldName the name of a field in error
|
||||
* @param errorCode the error code for that field
|
||||
*/
|
||||
public SELF hasFieldErrorCode(String fieldName, String errorCode) {
|
||||
Assertions.assertThat(getFieldError(fieldName).getCode())
|
||||
.as("check error code for field '%s'", fieldName).isEqualTo(errorCode);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
protected AssertionError unexpectedBindingResult(String reason, Object... arguments) {
|
||||
return this.failures.failure(this.info, new UnexpectedBindingResult(reason, arguments));
|
||||
}
|
||||
|
||||
private AssertProvider<ListAssert<String>> fieldErrorNames() {
|
||||
return () -> {
|
||||
List<String> actual = this.actual.getFieldErrors().stream().map(FieldError::getField).toList();
|
||||
return new ListAssert<>(actual).as("check field errors");
|
||||
};
|
||||
}
|
||||
|
||||
private FieldError getFieldError(String fieldName) {
|
||||
FieldError fieldError = this.actual.getFieldError(fieldName);
|
||||
if (fieldError == null) {
|
||||
throw unexpectedBindingResult("to have at least an error for field '%s'", fieldName);
|
||||
}
|
||||
return fieldError;
|
||||
}
|
||||
|
||||
|
||||
private final class UnexpectedBindingResult extends BasicErrorMessageFactory {
|
||||
|
||||
private UnexpectedBindingResult(String reason, Object... arguments) {
|
||||
super("%nExpecting binding result:%n %s%n%s", AbstractBindingResultAssert.this.actual,
|
||||
reason.formatted(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Testing support for validation.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.test.validation;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.validation.AbstractBindingResultAssert;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.BindingResultUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied to
|
||||
* a {@linkplain ModelAndView#getModel() model}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
public class ModelAssert extends AbstractMapAssert<ModelAssert, Map<String, Object>, String, Object> {
|
||||
|
||||
private final Failures failures = Failures.instance();
|
||||
|
||||
public ModelAssert(Map<String, Object> map) {
|
||||
super(map, ModelAssert.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain AbstractBindingResultAssert assertion} object
|
||||
* that uses the {@link BindingResult} with the given {@code name} as the
|
||||
* object to test.
|
||||
* Examples: <pre><code class='java'>
|
||||
* // Check that the "person" attribute in the model has 2 errors:
|
||||
* assertThat(...).model().extractingBindingResult("person").hasErrorsCount(2);
|
||||
* </code></pre>
|
||||
*/
|
||||
public AbstractBindingResultAssert<?> extractingBindingResult(String name) {
|
||||
BindingResult result = BindingResultUtils.getBindingResult(this.actual, name);
|
||||
if (result == null) {
|
||||
throw unexpectedModel("to have a binding result for attribute '%s'", name);
|
||||
}
|
||||
return new BindingResultAssert(name, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual model has at least one error.
|
||||
*/
|
||||
public ModelAssert hasErrors() {
|
||||
if (getAllErrors() == 0) {
|
||||
throw unexpectedModel("to have at least one error");
|
||||
}
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual model does not have any errors.
|
||||
*/
|
||||
public ModelAssert doesNotHaveErrors() {
|
||||
int count = getAllErrors(); if (count > 0) {
|
||||
throw unexpectedModel("to not have an error, but got %s", count);
|
||||
}
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual model contain the attributes with the given
|
||||
* {@code names}, and that these attributes have each at least one error.
|
||||
* @param names the expected names of attributes with errors
|
||||
*/
|
||||
public ModelAssert hasAttributeErrors(String... names) {
|
||||
return assertAttributes(names, BindingResult::hasErrors,
|
||||
"to have attribute errors for", "these attributes do not have any error");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual model contain the attributes with the given
|
||||
* {@code names}, and that these attributes do not have any error.
|
||||
* @param names the expected names of attributes without errors
|
||||
*/
|
||||
public ModelAssert doesNotHaveAttributeErrors(String... names) {
|
||||
return assertAttributes(names, Predicate.not(BindingResult::hasErrors),
|
||||
"to have attribute without errors for", "these attributes have at least an error");
|
||||
}
|
||||
|
||||
private ModelAssert assertAttributes(String[] names, Predicate<BindingResult> condition,
|
||||
String assertionMessage, String failAssertionMessage) {
|
||||
|
||||
Set<String> missing = new LinkedHashSet<>();
|
||||
Set<String> failCondition = new LinkedHashSet<>();
|
||||
for (String name : names) {
|
||||
BindingResult bindingResult = getBindingResult(name);
|
||||
if (bindingResult == null) {
|
||||
missing.add(name);
|
||||
}
|
||||
else if (!condition.test(bindingResult)) {
|
||||
failCondition.add(name);
|
||||
}
|
||||
}
|
||||
if (!missing.isEmpty() || !failCondition.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("%n%s:%n %s%n".formatted(assertionMessage, String.join(", ", names)));
|
||||
if (!missing.isEmpty()) {
|
||||
sb.append("%nbut could not find these attributes:%n %s%n".formatted(String.join(", ", missing)));
|
||||
}
|
||||
if (!failCondition.isEmpty()) {
|
||||
String prefix = missing.isEmpty() ? "but" : "and";
|
||||
sb.append("%n%s %s:%n %s%n".formatted(prefix, failAssertionMessage, String.join(", ", failCondition)));
|
||||
}
|
||||
throw unexpectedModel(sb.toString());
|
||||
}
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
private AssertionError unexpectedModel(String reason, Object... arguments) {
|
||||
return this.failures.failure(this.info, new UnexpectedModel(reason, arguments));
|
||||
}
|
||||
|
||||
private int getAllErrors() {
|
||||
return this.actual.values().stream().filter(Errors.class::isInstance).map(Errors.class::cast)
|
||||
.map(Errors::getErrorCount).reduce(0, Integer::sum);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BindingResult getBindingResult(String name) {
|
||||
return BindingResultUtils.getBindingResult(this.actual, name);
|
||||
}
|
||||
|
||||
private final class UnexpectedModel extends BasicErrorMessageFactory {
|
||||
|
||||
private UnexpectedModel(String reason, Object... arguments) {
|
||||
super("%nExpecting model:%n %s%n%s", ModelAssert.this.actual, reason.formatted(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BindingResultAssert extends AbstractBindingResultAssert<BindingResultAssert> {
|
||||
public BindingResultAssert(String name, BindingResult bindingResult) {
|
||||
super(name, bindingResult, BindingResultAssert.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.test.validation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.DataBinder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractBindingResultAssert}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class AbstractBindingResultAssertTests {
|
||||
|
||||
@Test
|
||||
void hasErrorsCountWithNoError() {
|
||||
assertThat(bindingResult(new TestBean(), Map.of("name", "John", "age", "42"))).hasErrorsCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrorsCountWithInvalidCount() {
|
||||
AssertProvider<BindingResultAssert> actual = bindingResult(new TestBean(),
|
||||
Map.of("name", "John", "age", "4x", "touchy", "invalid.value"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasErrorsCount(1))
|
||||
.withMessageContainingAll("check errors for attribute 'test'", "1", "2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasFieldErrorsWithMatchingSubset() {
|
||||
assertThat(bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y")))
|
||||
.hasFieldErrors("touchy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasFieldErrorsWithAllMatching() {
|
||||
assertThat(bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y")))
|
||||
.hasFieldErrors("touchy", "age");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasFieldErrorsWithNotAllMatching() {
|
||||
AssertProvider<BindingResultAssert> actual = bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasFieldErrors("age", "name"))
|
||||
.withMessageContainingAll("check field errors", "age", "touchy", "name");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasOnlyFieldErrorsWithAllMatching() {
|
||||
assertThat(bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y")))
|
||||
.hasOnlyFieldErrors("touchy", "age");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasOnlyFieldErrorsWithMatchingSubset() {
|
||||
AssertProvider<BindingResultAssert> actual = bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasOnlyFieldErrors("age"))
|
||||
.withMessageContainingAll("check field errors", "age", "touchy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasFieldErrorCodeWithMatchingCode() {
|
||||
assertThat(bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y")))
|
||||
.hasFieldErrorCode("age", "typeMismatch");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasFieldErrorCodeWitNonMatchingCode() {
|
||||
AssertProvider<BindingResultAssert> actual = bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasFieldErrorCode("age", "castFailure"))
|
||||
.withMessageContainingAll("check error code for field 'age'", "castFailure", "typeMismatch");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasFieldErrorCodeWitNonMatchingField() {
|
||||
AssertProvider<BindingResultAssert> actual = bindingResult(new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "x.y"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasFieldErrorCode("unknown", "whatever"))
|
||||
.withMessageContainingAll("Expecting binding result", "touchy", "age",
|
||||
"to have at least an error for field 'unknown'");
|
||||
}
|
||||
|
||||
|
||||
private AssertProvider<BindingResultAssert> bindingResult(Object instance, Map<String, Object> propertyValues) {
|
||||
return () -> new BindingResultAssert("test", createBindingResult(instance, propertyValues));
|
||||
}
|
||||
|
||||
private static BindingResult createBindingResult(Object instance, Map<String, Object> propertyValues) {
|
||||
DataBinder binder = new DataBinder(instance, "test");
|
||||
MutablePropertyValues pvs = new MutablePropertyValues(propertyValues);
|
||||
binder.bind(pvs);
|
||||
try {
|
||||
binder.close();
|
||||
return binder.getBindingResult();
|
||||
}
|
||||
catch (BindException ex) {
|
||||
return ex.getBindingResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class BindingResultAssert extends AbstractBindingResultAssert<BindingResultAssert> {
|
||||
public BindingResultAssert(String name, BindingResult bindingResult) {
|
||||
super(name, bindingResult, BindingResultAssert.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.DataBinder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* Tests for {@link ModelAssert}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ModelAssertTests {
|
||||
|
||||
@Test
|
||||
void hasErrors() {
|
||||
assertThat(forModel(new TestBean(), Map.of("name", "John", "age", "4x"))).hasErrors();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrorsWithNoError() {
|
||||
AssertProvider<ModelAssert> actual = forModel(new TestBean(), Map.of("name", "John", "age", "42"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(actual).hasErrors())
|
||||
.withMessageContainingAll("John", "to have at least one error");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotHaveErrors() {
|
||||
assertThat(forModel(new TestBean(), Map.of("name", "John", "age", "42"))).doesNotHaveErrors();
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotHaveErrorsWithError() {
|
||||
AssertProvider<ModelAssert> actual = forModel(new TestBean(), Map.of("name", "John", "age", "4x"));
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(actual).doesNotHaveErrors())
|
||||
.withMessageContainingAll("John", "to not have an error, but got 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void extractBindingResultForAttributeInError() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "person", new TestBean(), Map.of("name", "John", "age", "4x", "touchy", "invalid.value"));
|
||||
assertThat(forModel(model)).extractingBindingResult("person").hasErrorsCount(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrorCountForUnknownAttribute() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "person", new TestBean(), Map.of("name", "John", "age", "42"));
|
||||
AssertProvider<ModelAssert> actual = forModel(model);
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).extractingBindingResult("user"))
|
||||
.withMessageContainingAll("to have a binding result for attribute 'user'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrorsWithMatchingAttributes() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "wrong1", new TestBean(), Map.of("name", "first", "age", "4x"));
|
||||
augmentModel(model, "valid", new TestBean(), Map.of("name", "second"));
|
||||
augmentModel(model, "wrong2", new TestBean(), Map.of("name", "third", "touchy", "invalid.name"));
|
||||
assertThat(forModel(model)).hasAttributeErrors("wrong1", "wrong2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrorsWithOneNonMatchingAttribute() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "wrong1", new TestBean(), Map.of("name", "first", "age", "4x"));
|
||||
augmentModel(model, "valid", new TestBean(), Map.of("name", "second"));
|
||||
augmentModel(model, "wrong2", new TestBean(), Map.of("name", "third", "touchy", "invalid.name"));
|
||||
AssertProvider<ModelAssert> actual = forModel(model);
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasAttributeErrors("wrong1", "valid"))
|
||||
.withMessageContainingAll("to have attribute errors for:", "wrong1, valid",
|
||||
"but these attributes do not have any error:", "valid");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrorsWithOneNonMatchingAttributeAndOneUnknownAttribute() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "wrong1", new TestBean(), Map.of("name", "first", "age", "4x"));
|
||||
augmentModel(model, "valid", new TestBean(), Map.of("name", "second"));
|
||||
augmentModel(model, "wrong2", new TestBean(), Map.of("name", "third", "touchy", "invalid.name"));
|
||||
AssertProvider<ModelAssert> actual = forModel(model);
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).hasAttributeErrors("wrong1", "unknown", "valid"))
|
||||
.withMessageContainingAll("to have attribute errors for:", "wrong1, unknown, valid",
|
||||
"but could not find these attributes:", "unknown",
|
||||
"and these attributes do not have any error:", "valid");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotHaveErrorsWithMatchingAttributes() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "valid1", new TestBean(), Map.of("name", "first"));
|
||||
augmentModel(model, "wrong", new TestBean(), Map.of("name", "second", "age", "4x"));
|
||||
augmentModel(model, "valid2", new TestBean(), Map.of("name", "third"));
|
||||
assertThat(forModel(model)).doesNotHaveAttributeErrors("valid1", "valid2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotHaveErrorsWithOneNonMatchingAttribute() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "valid1", new TestBean(), Map.of("name", "first"));
|
||||
augmentModel(model, "wrong", new TestBean(), Map.of("name", "second", "age", "4x"));
|
||||
augmentModel(model, "valid2", new TestBean(), Map.of("name", "third"));
|
||||
AssertProvider<ModelAssert> actual = forModel(model);
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).doesNotHaveAttributeErrors("valid1", "wrong"))
|
||||
.withMessageContainingAll("to have attribute without errors for:", "valid1, wrong",
|
||||
"but these attributes have at least an error:", "wrong");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotHaveErrorsWithOneNonMatchingAttributeAndOneUnknownAttribute() {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "valid1", new TestBean(), Map.of("name", "first"));
|
||||
augmentModel(model, "wrong", new TestBean(), Map.of("name", "second", "age", "4x"));
|
||||
augmentModel(model, "valid2", new TestBean(), Map.of("name", "third"));
|
||||
AssertProvider<ModelAssert> actual = forModel(model);
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(
|
||||
() -> assertThat(actual).doesNotHaveAttributeErrors("valid1", "unknown", "wrong"))
|
||||
.withMessageContainingAll("to have attribute without errors for:", "valid1, unknown, wrong",
|
||||
"but could not find these attributes:", "unknown",
|
||||
"and these attributes have at least an error:", "wrong");
|
||||
}
|
||||
|
||||
private AssertProvider<ModelAssert> forModel(Map<String, Object> model) {
|
||||
return () -> new ModelAssert(model);
|
||||
}
|
||||
|
||||
private AssertProvider<ModelAssert> forModel(Object instance, Map<String, Object> propertyValues) {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
augmentModel(model, "test", instance, propertyValues);
|
||||
return forModel(model);
|
||||
}
|
||||
|
||||
private static void augmentModel(Map<String, Object> model, String attribute, Object instance, Map<String, Object> propertyValues) {
|
||||
DataBinder binder = new DataBinder(instance, attribute);
|
||||
MutablePropertyValues pvs = new MutablePropertyValues(propertyValues);
|
||||
binder.bind(pvs);
|
||||
try {
|
||||
binder.close();
|
||||
model.putAll(binder.getBindingResult().getModel());
|
||||
}
|
||||
catch (BindException ex) {
|
||||
model.putAll(ex.getBindingResult().getModel());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user