Polishing in [Rest|Web]TestClient Assertions

See gh-34428
This commit is contained in:
rstoyanchev 2025-07-29 21:09:20 +01:00
parent 6cc1310274
commit 88ddc9d45d
23 changed files with 561 additions and 1005 deletions

View File

@ -36,12 +36,13 @@ public class CookieAssertions extends AbstractCookieAssertions<ExchangeResult, W
@Override @Override
protected void assertWithDiagnostics(Runnable assertion) { protected MultiValueMap<String, ResponseCookie> getResponseCookies() {
exchangeResult.assertWithDiagnostics(assertion); return getExchangeResult().getResponseCookies();
} }
@Override @Override
protected MultiValueMap<String, ResponseCookie> getResponseCookies() { protected void assertWithDiagnostics(Runnable assertion) {
return exchangeResult.getResponseCookies(); getExchangeResult().assertWithDiagnostics(assertion);
} }
} }

View File

@ -38,12 +38,13 @@ public class HeaderAssertions extends AbstractHeaderAssertions<ExchangeResult, W
@Override @Override
protected void assertWithDiagnostics(Runnable assertion) { protected HttpHeaders getResponseHeaders() {
exchangeResult.assertWithDiagnostics(assertion); return getExchangeResult().getResponseHeaders();
} }
@Override @Override
protected HttpHeaders getResponseHeaders() { protected void assertWithDiagnostics(Runnable assertion) {
return exchangeResult.getResponseHeaders(); getExchangeResult().assertWithDiagnostics(assertion);
} }
} }

View File

@ -36,12 +36,13 @@ public class StatusAssertions extends AbstractStatusAssertions<ExchangeResult, W
@Override @Override
protected void assertWithDiagnostics(Runnable assertion) { protected HttpStatusCode getStatus() {
exchangeResult.assertWithDiagnostics(assertion); return getExchangeResult().getStatus();
} }
@Override @Override
protected HttpStatusCode getStatus() { protected void assertWithDiagnostics(Runnable assertion) {
return exchangeResult.getStatus(); getExchangeResult().assertWithDiagnostics(assertion);
} }
} }

View File

@ -35,20 +35,23 @@ import org.springframework.util.Assert;
*/ */
public class XpathAssertions extends AbstractXpathAssertions<WebTestClient.BodyContentSpec> { public class XpathAssertions extends AbstractXpathAssertions<WebTestClient.BodyContentSpec> {
XpathAssertions(WebTestClient.BodyContentSpec spec,
XpathAssertions(
WebTestClient.BodyContentSpec spec,
String expression, @Nullable Map<String, String> namespaces, Object... args) { String expression, @Nullable Map<String, String> namespaces, Object... args) {
super(spec, expression, namespaces, args); super(spec, expression, namespaces, args);
} }
@Override @Override
protected Optional<HttpHeaders> getResponseHeaders() { protected Optional<HttpHeaders> getResponseHeaders() {
return Optional.of(bodySpec.returnResult()) return Optional.of(getBodySpec().returnResult()).map(ExchangeResult::getResponseHeaders);
.map(ExchangeResult::getResponseHeaders);
} }
@Override @Override
protected byte[] getContent() { protected byte[] getContent() {
byte[] body = this.bodySpec.returnResult().getResponseBody(); byte[] body = getBodySpec().returnResult().getResponseBody();
Assert.notNull(body, "Expected body content"); Assert.notNull(body, "Expected body content");
return body; return body;
} }

View File

@ -35,12 +35,13 @@ public class CookieAssertions extends AbstractCookieAssertions<ExchangeResult, R
@Override @Override
protected void assertWithDiagnostics(Runnable assertion) { protected MultiValueMap<String, ResponseCookie> getResponseCookies() {
exchangeResult.assertWithDiagnostics(assertion); return getExchangeResult().getResponseCookies();
} }
@Override @Override
protected MultiValueMap<String, ResponseCookie> getResponseCookies() { protected void assertWithDiagnostics(Runnable assertion) {
return exchangeResult.getResponseCookies(); getExchangeResult().assertWithDiagnostics(assertion);
} }
} }

View File

@ -23,6 +23,7 @@ import org.jspecify.annotations.Nullable;
* extracted to a representation of type {@code <T>}. * extracted to a representation of type {@code <T>}.
* *
* @author Rob Worsnop * @author Rob Worsnop
* @since 7.0
* @param <T> the response body type * @param <T> the response body type
*/ */
public class EntityExchangeResult<T> extends ExchangeResult { public class EntityExchangeResult<T> extends ExchangeResult {

View File

@ -33,13 +33,15 @@ public class HeaderAssertions extends AbstractHeaderAssertions<ExchangeResult, R
super(exchangeResult, responseSpec); super(exchangeResult, responseSpec);
} }
@Override
protected void assertWithDiagnostics(Runnable assertion) {
exchangeResult.assertWithDiagnostics(assertion);
}
@Override @Override
protected HttpHeaders getResponseHeaders() { protected HttpHeaders getResponseHeaders() {
return exchangeResult.getResponseHeaders(); return getExchangeResult().getResponseHeaders();
} }
@Override
protected void assertWithDiagnostics(Runnable assertion) {
getExchangeResult().assertWithDiagnostics(assertion);
}
} }

View File

@ -36,12 +36,13 @@ public class StatusAssertions extends AbstractStatusAssertions<ExchangeResult, R
@Override @Override
protected void assertWithDiagnostics(Runnable assertion) { protected HttpStatusCode getStatus() {
exchangeResult.assertWithDiagnostics(assertion); return getExchangeResult().getStatus();
} }
@Override @Override
protected HttpStatusCode getStatus() { protected void assertWithDiagnostics(Runnable assertion) {
return exchangeResult.getStatus(); getExchangeResult().assertWithDiagnostics(assertion);
} }
} }

View File

@ -44,13 +44,12 @@ public class XpathAssertions extends AbstractXpathAssertions<RestTestClient.Body
@Override @Override
protected Optional<HttpHeaders> getResponseHeaders() { protected Optional<HttpHeaders> getResponseHeaders() {
return Optional.of(bodySpec.returnResult()) return Optional.of(getBodySpec().returnResult()).map(ExchangeResult::getResponseHeaders);
.map(ExchangeResult::getResponseHeaders);
} }
@Override @Override
protected byte[] getContent() { protected byte[] getContent() {
byte[] body = this.bodySpec.returnResult().getResponseBody(); byte[] body = getBodySpec().returnResult().getResponseBody();
Assert.notNull(body, "Expected body content"); Assert.notNull(body, "Expected body content");
return body; return body;
} }

View File

@ -1,8 +1,7 @@
/** /**
* Support for testing Spring MVC applications via * Support for testing Spring MVC applications via
* {@link org.springframework.test.web.reactive.server.WebTestClient} * {@link org.springframework.test.web.servlet.client.RestTestClient} with
* with {@link org.springframework.test.web.servlet.MockMvc} for server request * {@link org.springframework.test.web.servlet.MockMvc} for server request handling.
* handling.
*/ */
@NullMarked @NullMarked

View File

@ -34,19 +34,42 @@ import static org.springframework.test.util.AssertionErrors.fail;
* Assertions on cookies of the response. * Assertions on cookies of the response.
* *
* @author Rob Worsnop * @author Rob Worsnop
* @author Rossen Stoyanchev
* @since 7.0 * @since 7.0
* @param <E> the type of the exchange result * @param <E> the type of the exchange result
* @param <R> the type of the response spec * @param <R> the type of the response spec
*/ */
public abstract class AbstractCookieAssertions<E, R> { public abstract class AbstractCookieAssertions<E, R> {
protected final E exchangeResult;
private final E exchangeResult;
private final R responseSpec; private final R responseSpec;
protected AbstractCookieAssertions(E exchangeResult, R responseSpec) { protected AbstractCookieAssertions(E exchangeResult, R responseSpec) {
this.exchangeResult = exchangeResult; this.exchangeResult = exchangeResult;
this.responseSpec = responseSpec; this.responseSpec = responseSpec;
} }
/**
* Return the exchange result.
*/
protected E getExchangeResult() {
return this.exchangeResult;
}
/**
* Subclasses must implement this to provide access to response cookies.
*/
protected abstract MultiValueMap<String, ResponseCookie> getResponseCookies();
/**
* Subclasses must implement this to assert with diagnostics.
*/
protected abstract void assertWithDiagnostics(Runnable assertion);
/** /**
* Expect a response cookie with the given name to match the specified value. * Expect a response cookie with the given name to match the specified value.
*/ */
@ -224,10 +247,6 @@ public abstract class AbstractCookieAssertions<E, R> {
return this.responseSpec; return this.responseSpec;
} }
protected abstract void assertWithDiagnostics(Runnable assertion);
protected abstract MultiValueMap<String, ResponseCookie> getResponseCookies();
private ResponseCookie getCookie(String name) { private ResponseCookie getCookie(String name) {
ResponseCookie cookie = getResponseCookies().getFirst(name); ResponseCookie cookie = getResponseCookies().getFirst(name);
if (cookie != null) { if (cookie != null) {

View File

@ -40,19 +40,42 @@ import static org.springframework.test.util.AssertionErrors.fail;
* Assertions on headers of the response. * Assertions on headers of the response.
* *
* @author Rob Worsnop * @author Rob Worsnop
* @author Rossen Stoyanchev
* @since 7.0 * @since 7.0
* @param <E> the type of the exchange result * @param <E> the type of the exchange result
* @param <R> the type of the response spec * @param <R> the type of the response spec
*/ */
public abstract class AbstractHeaderAssertions <E, R> { public abstract class AbstractHeaderAssertions <E, R> {
protected final E exchangeResult;
private final E exchangeResult;
private final R responseSpec; private final R responseSpec;
protected AbstractHeaderAssertions(E exchangeResult, R responseSpec) { protected AbstractHeaderAssertions(E exchangeResult, R responseSpec) {
this.exchangeResult = exchangeResult; this.exchangeResult = exchangeResult;
this.responseSpec = responseSpec; this.responseSpec = responseSpec;
} }
/**
* Return the exchange result.
*/
protected E getExchangeResult() {
return this.exchangeResult;
}
/**
* Subclasses must implement this to provide access to response headers.
*/
protected abstract HttpHeaders getResponseHeaders();
/**
* Subclasses must implement this to assert with diagnostics.
*/
protected abstract void assertWithDiagnostics(Runnable assertion);
/** /**
* Expect a header with the given name to match the specified values. * Expect a header with the given name to match the specified values.
*/ */
@ -277,10 +300,6 @@ public abstract class AbstractHeaderAssertions <E, R> {
return assertHeader("Location", URI.create(location), getResponseHeaders().getLocation()); return assertHeader("Location", URI.create(location), getResponseHeaders().getLocation());
} }
protected abstract void assertWithDiagnostics(Runnable assertion);
protected abstract HttpHeaders getResponseHeaders();
private R assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { private R assertHeader(String name, @Nullable Object expected, @Nullable Object actual) {
assertWithDiagnostics(() -> { assertWithDiagnostics(() -> {
String message = getMessage(name); String message = getMessage(name);

View File

@ -26,6 +26,18 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.test.util.JsonPathExpectationsHelper; import org.springframework.test.util.JsonPathExpectationsHelper;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/**
* Base class for applying
* <a href="https://github.com/jayway/JsonPath">JsonPath</a> assertions
* in RestTestClient and WebTestClient.
*
* @author Rob Worsnop
* @author Rossen Stoyanchev
* @since 7.0
* @param <B> the type of body spec (RestTestClient vs WebTestClient specific)
* @see <a href="https://github.com/jayway/JsonPath">https://github.com/jayway/JsonPath</a>
* @see JsonPathExpectationsHelper
*/
public abstract class AbstractJsonPathAssertions<B> { public abstract class AbstractJsonPathAssertions<B> {
private final B bodySpec; private final B bodySpec;
@ -34,6 +46,7 @@ public abstract class AbstractJsonPathAssertions<B> {
private final JsonPathExpectationsHelper pathHelper; private final JsonPathExpectationsHelper pathHelper;
protected AbstractJsonPathAssertions(B spec, String content, String expression, @Nullable Configuration configuration) { protected AbstractJsonPathAssertions(B spec, String content, String expression, @Nullable Configuration configuration) {
Assert.hasText(expression, "expression must not be null or empty"); Assert.hasText(expression, "expression must not be null or empty");
this.bodySpec = spec; this.bodySpec = spec;
@ -41,6 +54,7 @@ public abstract class AbstractJsonPathAssertions<B> {
this.pathHelper = new JsonPathExpectationsHelper(expression, configuration); this.pathHelper = new JsonPathExpectationsHelper(expression, configuration);
} }
/** /**
* Applies {@link JsonPathExpectationsHelper#assertValue(String, Object)}. * Applies {@link JsonPathExpectationsHelper#assertValue(String, Object)}.
*/ */

View File

@ -31,18 +31,42 @@ import static org.springframework.test.util.AssertionErrors.assertNotNull;
* Assertions on the response status. * Assertions on the response status.
* *
* @author Rob Worsnop * @author Rob Worsnop
* @author Rossen Stoyanchev
* @since 7.0
* @param <E> the type of the exchange result * @param <E> the type of the exchange result
* @param <R> the type of the response spec * @param <R> the type of the response spec
*/ */
public abstract class AbstractStatusAssertions<E, R> { public abstract class AbstractStatusAssertions<E, R> {
protected final E exchangeResult;
private final E exchangeResult;
private final R responseSpec; private final R responseSpec;
protected AbstractStatusAssertions(E exchangeResult, R responseSpec) { protected AbstractStatusAssertions(E exchangeResult, R responseSpec) {
this.exchangeResult = exchangeResult; this.exchangeResult = exchangeResult;
this.responseSpec = responseSpec; this.responseSpec = responseSpec;
} }
/**
* Return the exchange result.
*/
protected E getExchangeResult() {
return this.exchangeResult;
}
/**
* Subclasses must implement this to provide access to the response status.
*/
protected abstract HttpStatusCode getStatus();
/**
* Subclasses must implement this to assert with diagnostics.
*/
protected abstract void assertWithDiagnostics(Runnable assertion);
/** /**
* Assert the response status as an {@link HttpStatusCode}. * Assert the response status as an {@link HttpStatusCode}.
*/ */
@ -226,10 +250,6 @@ public abstract class AbstractStatusAssertions<E, R> {
return this.responseSpec; return this.responseSpec;
} }
protected abstract void assertWithDiagnostics(Runnable assertion);
protected abstract HttpStatusCode getStatus();
private R assertStatusAndReturn(HttpStatus expected) { private R assertStatusAndReturn(HttpStatus expected) {
assertNotNull("exchangeResult unexpectedly null", this.exchangeResult); assertNotNull("exchangeResult unexpectedly null", this.exchangeResult);
HttpStatusCode actual = getStatus(); HttpStatusCode actual = getStatus();

View File

@ -30,12 +30,24 @@ import org.springframework.http.HttpHeaders;
import org.springframework.test.util.XpathExpectationsHelper; import org.springframework.test.util.XpathExpectationsHelper;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
/**
* Base class for applying XPath assertions in RestTestClient and WebTestClient.
*
* @author Rob Worsnop
* @author Rossen Stoyanchev
* @since 7.0
* @param <B> the type of body spec (RestTestClient vs WebTestClient specific)
*/
public abstract class AbstractXpathAssertions<B> { public abstract class AbstractXpathAssertions<B> {
protected final B bodySpec;
private final B bodySpec;
private final XpathExpectationsHelper xpathHelper; private final XpathExpectationsHelper xpathHelper;
public AbstractXpathAssertions(B spec, String expression, @Nullable Map<String, String> namespaces, Object... args) {
public AbstractXpathAssertions(
B spec, String expression, @Nullable Map<String, String> namespaces, Object... args) {
this.bodySpec = spec; this.bodySpec = spec;
this.xpathHelper = initXpathHelper(expression, namespaces, args); this.xpathHelper = initXpathHelper(expression, namespaces, args);
} }
@ -52,6 +64,24 @@ public abstract class AbstractXpathAssertions<B> {
} }
/**
* Return the body spec.
*/
protected B getBodySpec() {
return this.bodySpec;
}
/**
* Subclasses must implement this to provide access to response headers.
*/
protected abstract Optional<HttpHeaders> getResponseHeaders();
/**
* Subclasses must implement this to provide access to the response content.
*/
protected abstract byte[] getContent();
/** /**
* Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, String)}. * Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, String)}.
*/ */
@ -175,9 +205,6 @@ public abstract class AbstractXpathAssertions<B> {
return super.hashCode(); return super.hashCode();
} }
protected abstract Optional<HttpHeaders> getResponseHeaders();
protected abstract byte[] getContent();
/** /**
* Lets us be able to use lambda expressions that could throw checked exceptions, since * Lets us be able to use lambda expressions that could throw checked exceptions, since

View File

@ -1,145 +0,0 @@
/*
* Copyright 2002-present 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.reactive.server;
import java.net.URI;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.mock.http.client.reactive.MockClientHttpRequest;
import org.springframework.mock.http.client.reactive.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link CookieAssertions}
*
* @author Rossen Stoyanchev
*/
public class CookieAssertionsTests {
private final ResponseCookie cookie = ResponseCookie.from("foo", "bar")
.maxAge(Duration.ofMinutes(30))
.domain("foo.com")
.path("/foo")
.secure(true)
.httpOnly(true)
.partitioned(true)
.sameSite("Lax")
.build();
private final CookieAssertions assertions = cookieAssertions(cookie);
@Test
void valueEquals() {
assertions.valueEquals("foo", "bar");
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.valueEquals("what?!", "bar"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.valueEquals("foo", "what?!"));
}
@Test
void value() {
assertions.value("foo", equalTo("bar"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.value("foo", equalTo("what?!")));
}
@Test
void exists() {
assertions.exists("foo");
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.exists("what?!"));
}
@Test
void doesNotExist() {
assertions.doesNotExist("what?!");
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.doesNotExist("foo"));
}
@Test
void maxAge() {
assertions.maxAge("foo", Duration.ofMinutes(30));
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.maxAge("foo", Duration.ofMinutes(29)));
assertions.maxAge("foo", equalTo(Duration.ofMinutes(30).getSeconds()));
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.maxAge("foo", equalTo(Duration.ofMinutes(29).getSeconds())));
}
@Test
void domain() {
assertions.domain("foo", "foo.com");
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.domain("foo", "what.com"));
assertions.domain("foo", equalTo("foo.com"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.domain("foo", equalTo("what.com")));
}
@Test
void path() {
assertions.path("foo", "/foo");
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.path("foo", "/what"));
assertions.path("foo", equalTo("/foo"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.path("foo", equalTo("/what")));
}
@Test
void secure() {
assertions.secure("foo", true);
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.secure("foo", false));
}
@Test
void httpOnly() {
assertions.httpOnly("foo", true);
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.httpOnly("foo", false));
}
@Test
void partitioned() {
assertions.partitioned("foo", true);
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.partitioned("foo", false));
}
@Test
void sameSite() {
assertions.sameSite("foo", "Lax");
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.sameSite("foo", "Strict"));
}
private CookieAssertions cookieAssertions(ResponseCookie cookie) {
MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/"));
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
response.getCookies().add(cookie.getName(), cookie);
ExchangeResult result = new ExchangeResult(
request, response, Mono.empty(), Mono.empty(), Duration.ZERO, null, null);
return new CookieAssertions(result, mock());
}
}

View File

@ -1,259 +0,0 @@
/*
* Copyright 2002-present 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.reactive.server;
import java.net.URI;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.http.client.reactive.MockClientHttpRequest;
import org.springframework.mock.http.client.reactive.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItems;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link HeaderAssertions}.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
*/
class HeaderAssertionTests {
@Test
void valueEquals() {
HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar");
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.valueEquals("foo", "bar");
// Missing header
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.valueEquals("what?!", "bar"));
// Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.valueEquals("foo", "what?!"));
// Wrong # of values
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.valueEquals("foo", "bar", "what?!"));
}
@Test
void valueEqualsWithMultipleValues() {
HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar");
headers.add("foo", "baz");
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.valueEquals("foo", "bar", "baz");
// Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.valueEquals("foo", "bar", "what?!"));
// Too few values
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.valueEquals("foo", "bar"));
}
@Test
void valueMatches() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.valueMatches("Content-Type", ".*UTF-8.*");
// Wrong pattern
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.valueMatches("Content-Type", ".*ISO-8859-1.*"))
.satisfies(ex -> assertThat(ex).hasMessage("Response header " +
"'Content-Type'=[application/json;charset=UTF-8] does not match " +
"[.*ISO-8859-1.*]"));
}
@Test
void valueMatchesWithNonexistentHeader() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
HeaderAssertions assertions = headerAssertions(headers);
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.valueMatches("Content-XYZ", ".*ISO-8859-1.*"))
.withMessage("Response header 'Content-XYZ' not found");
}
@Test
void valuesMatch() {
HttpHeaders headers = new HttpHeaders();
headers.add("foo", "value1");
headers.add("foo", "value2");
headers.add("foo", "value3");
HeaderAssertions assertions = headerAssertions(headers);
assertions.valuesMatch("foo", "val.*1", "val.*2", "val.*3");
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.valuesMatch("foo", ".*", "val.*5"))
.satisfies(ex -> assertThat(ex).hasMessage(
"Response header 'foo' has fewer or more values [value1, value2, value3] " +
"than number of patterns to match with [.*, val.*5]"));
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.valuesMatch("foo", ".*", "val.*5", ".*"))
.satisfies(ex -> assertThat(ex).hasMessage(
"Response header 'foo'[1]='value2' does not match 'val.*5'"));
}
@Test
void valueMatcher() {
HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar");
HeaderAssertions assertions = headerAssertions(headers);
assertions.value("foo", containsString("a"));
}
@Test
void valuesMatcher() {
HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar");
headers.add("foo", "baz");
HeaderAssertions assertions = headerAssertions(headers);
assertions.values("foo", hasItems("bar", "baz"));
}
@Test
void exists() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.exists("Content-Type");
// Header should not exist
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.exists("Framework"))
.satisfies(ex -> assertThat(ex).hasMessage("Response header 'Framework' does not exist"));
}
@Test
void doesNotExist() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.doesNotExist("Framework");
// Existing header
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.doesNotExist("Content-Type"))
.satisfies(ex -> assertThat(ex).hasMessage("Response header " +
"'Content-Type' exists with value=[application/json;charset=UTF-8]"));
}
@Test
void contentTypeCompatibleWith() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.contentTypeCompatibleWith(MediaType.parseMediaType("application/*"));
// MediaTypes not compatible
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.contentTypeCompatibleWith(MediaType.TEXT_XML))
.withMessage("Response header 'Content-Type'=[application/xml] is not compatible with [text/xml]");
}
@Test
void cacheControl() {
CacheControl control = CacheControl.maxAge(1, TimeUnit.HOURS).noTransform();
HttpHeaders headers = new HttpHeaders();
headers.setCacheControl(control.getHeaderValue());
HeaderAssertions assertions = headerAssertions(headers);
// Success
assertions.cacheControl(control);
// Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.cacheControl(CacheControl.noStore()));
}
@Test
void expires() {
HttpHeaders headers = new HttpHeaders();
ZonedDateTime expires = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"));
headers.setExpires(expires);
HeaderAssertions assertions = headerAssertions(headers);
assertions.expires(expires.toInstant().toEpochMilli());
// Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.expires(expires.toInstant().toEpochMilli() + 1));
}
@Test
void lastModified() {
HttpHeaders headers = new HttpHeaders();
ZonedDateTime lastModified = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"));
headers.setLastModified(lastModified.toInstant().toEpochMilli());
HeaderAssertions assertions = headerAssertions(headers);
assertions.lastModified(lastModified.toInstant().toEpochMilli());
// Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.lastModified(lastModified.toInstant().toEpochMilli() + 1));
}
private HeaderAssertions headerAssertions(HttpHeaders responseHeaders) {
MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/"));
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
response.getHeaders().putAll(responseHeaders);
ExchangeResult result = new ExchangeResult(
request, response, Mono.empty(), Mono.empty(), Duration.ZERO, null, null);
return new HeaderAssertions(result, mock());
}
}

View File

@ -1,176 +0,0 @@
/*
* Copyright 2002-present 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.reactive.server;
import java.net.URI;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.mock.http.client.reactive.MockClientHttpRequest;
import org.springframework.mock.http.client.reactive.MockClientHttpResponse;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link StatusAssertions}.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
*/
class StatusAssertionTests {
@Test
void isEqualTo() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.isEqualTo(HttpStatus.CONFLICT);
assertions.isEqualTo(409);
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(HttpStatus.REQUEST_TIMEOUT));
// Wrong status value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(408));
}
@Test // gh-23630, gh-29283
void isEqualToWithCustomStatus() {
StatusAssertions assertions = statusAssertions(600);
// Success
// assertions.isEqualTo(600);
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(HttpStatus.REQUEST_TIMEOUT));
// Wrong status value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(408));
}
@Test
void reasonEquals() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.reasonEquals("Conflict");
// Wrong reason
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.reasonEquals("Request Timeout"));
}
@Test
void statusSeries1xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONTINUE);
// Success
assertions.is1xxInformational();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(assertions::is2xxSuccessful);
}
@Test
void statusSeries2xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.OK);
// Success
assertions.is2xxSuccessful();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(assertions::is5xxServerError);
}
@Test
void statusSeries3xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.PERMANENT_REDIRECT);
// Success
assertions.is3xxRedirection();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(assertions::is2xxSuccessful);
}
@Test
void statusSeries4xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.BAD_REQUEST);
// Success
assertions.is4xxClientError();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(assertions::is2xxSuccessful);
}
@Test
void statusSeries5xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR);
// Success
assertions.is5xxServerError();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(assertions::is2xxSuccessful);
}
@Test
void matchesStatusValue() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.value(equalTo(409));
assertions.value(greaterThan(400));
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.value(equalTo(200)));
}
@Test // gh-26658
void matchesCustomStatusValue() {
statusAssertions(600).value(equalTo(600));
}
private StatusAssertions statusAssertions(HttpStatus status) {
return statusAssertions(status.value());
}
private StatusAssertions statusAssertions(int status) {
MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/"));
MockClientHttpResponse response = new MockClientHttpResponse(status);
ExchangeResult result = new ExchangeResult(
request, response, Mono.empty(), Mono.empty(), Duration.ZERO, null, null);
return new StatusAssertions(result, mock());
}
}

View File

@ -1,269 +0,0 @@
/*
* Copyright 2002-present 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.client;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.web.client.RestClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.mockito.BDDMockito.mock;
import static org.mockito.BDDMockito.when;
/**
* Tests for {@link StatusAssertions}.
*
* @author Rob Worsnop
*/
class StatusAssertionTests {
@Test
void isEqualTo() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.isEqualTo(HttpStatus.CONFLICT);
assertions.isEqualTo(409);
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(HttpStatus.REQUEST_TIMEOUT));
// Wrong status value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.isEqualTo(408));
}
@Test
void isEqualToWithCustomStatus() {
StatusAssertions assertions = statusAssertions(600);
// Success
assertions.isEqualTo(600);
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(601).isEqualTo(600));
}
@Test
void reasonEquals() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.reasonEquals("Conflict");
// Wrong reason
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).reasonEquals("Conflict"));
}
@Test
void statusSeries1xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONTINUE);
// Success
assertions.is1xxInformational();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(HttpStatus.OK).is1xxInformational());
}
@Test
void statusSeries2xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.OK);
// Success
assertions.is2xxSuccessful();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).is2xxSuccessful());
}
@Test
void statusSeries3xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.PERMANENT_REDIRECT);
// Success
assertions.is3xxRedirection();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).is3xxRedirection());
}
@Test
void statusSeries4xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.BAD_REQUEST);
// Success
assertions.is4xxClientError();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).is4xxClientError());
}
@Test
void statusSeries5xx() {
StatusAssertions assertions = statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR);
// Success
assertions.is5xxServerError();
// Wrong series
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
statusAssertions(HttpStatus.OK).is5xxServerError());
}
@Test
void matchesStatusValue() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.value(equalTo(409));
assertions.value(greaterThan(400));
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertions.value(equalTo(200)));
}
@Test
void matchesCustomStatusValue() {
statusAssertions(600).value(equalTo(600));
}
@Test
void consumesStatusValue() {
StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT);
// Success
assertions.value((Integer value) -> assertThat(value).isEqualTo(409));
}
@Test
void statusIsAccepted() {
// Success
statusAssertions(HttpStatus.ACCEPTED).isAccepted();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isAccepted());
}
@Test
void statusIsNoContent() {
// Success
statusAssertions(HttpStatus.NO_CONTENT).isNoContent();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isNoContent());
}
@Test
void statusIsFound() {
// Success
statusAssertions(HttpStatus.FOUND).isFound();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isFound());
}
@Test
void statusIsSeeOther() {
// Success
statusAssertions(HttpStatus.SEE_OTHER).isSeeOther();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isSeeOther());
}
@Test
void statusIsNotModified() {
// Success
statusAssertions(HttpStatus.NOT_MODIFIED).isNotModified();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isNotModified());
}
@Test
void statusIsTemporaryRedirect() {
// Success
statusAssertions(HttpStatus.TEMPORARY_REDIRECT).isTemporaryRedirect();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isTemporaryRedirect());
}
@Test
void statusIsPermanentRedirect() {
// Success
statusAssertions(HttpStatus.PERMANENT_REDIRECT).isPermanentRedirect();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isPermanentRedirect());
}
@Test
void statusIsUnauthorized() {
// Success
statusAssertions(HttpStatus.UNAUTHORIZED).isUnauthorized();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isUnauthorized());
}
@Test
void statusIsForbidden() {
// Success
statusAssertions(HttpStatus.FORBIDDEN).isForbidden();
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> statusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isForbidden());
}
private StatusAssertions statusAssertions(HttpStatus status) {
return statusAssertions(status.value());
}
private StatusAssertions statusAssertions(int status) {
try {
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response = mock();
when(response.getStatusCode()).thenReturn(HttpStatusCode.valueOf(status));
when(response.getHeaders()).thenReturn(new HttpHeaders());
ExchangeResult result = new ExchangeResult(new MockClientHttpRequest(), response, null);
return new StatusAssertions(result, mock());
}
catch (IOException ex) {
throw new AssertionError(ex);
}
}
}

View File

@ -14,34 +14,37 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.test.web.servlet.client; package org.springframework.test.web.support;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.mock.http.client.MockClientHttpRequest; import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClient;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.mockito.BDDMockito.mock;
import static org.mockito.BDDMockito.when;
/** /**
* Tests for {@link CookieAssertions} * Tests for {@link AbstractCookieAssertions}.
* *
* @author Rob Worsnop * @author Rob Worsnop
* @author Rossen Stoyanchev
*/ */
public class CookieAssertionsTests { public class CookieAssertionsTests {
private final ResponseCookie cookie = ResponseCookie.from("foo", "bar") private TestCookieAssertions assertions;
@BeforeEach
void setUp() throws IOException {
ResponseCookie cookie = ResponseCookie.from("foo", "bar")
.maxAge(Duration.ofMinutes(30)) .maxAge(Duration.ofMinutes(30))
.domain("foo.com") .domain("foo.com")
.path("/foo") .path("/foo")
@ -51,14 +54,10 @@ public class CookieAssertionsTests {
.sameSite("Lax") .sameSite("Lax")
.build(); .build();
private CookieAssertions assertions; this.assertions = initCookieAssertions(cookie);
@BeforeEach
void setUp() throws IOException {
this.assertions = cookieAssertions(cookie);
} }
@Test @Test
void valueEquals() { void valueEquals() {
assertions.valueEquals("foo", "bar"); assertions.valueEquals("foo", "bar");
@ -75,7 +74,8 @@ public class CookieAssertionsTests {
@Test @Test
void valueConsumer() { void valueConsumer() {
assertions.value("foo", input -> assertThat(input).isEqualTo("bar")); assertions.value("foo", input -> assertThat(input).isEqualTo("bar"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.value("foo", input -> assertThat(input).isEqualTo("what?!"))); assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.value("foo", input -> assertThat(input).isEqualTo("what?!")));
} }
@Test @Test
@ -143,15 +143,31 @@ public class CookieAssertionsTests {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.sameSite("foo", "Strict")); assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.sameSite("foo", "Strict"));
} }
private TestCookieAssertions initCookieAssertions(ResponseCookie cookie) throws IOException {
return new TestCookieAssertions(cookie);
}
private CookieAssertions cookieAssertions(ResponseCookie cookie) throws IOException {
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response = mock(); private static class TestCookieAssertions extends AbstractCookieAssertions<TestExchangeResult, Object> {
var headers = new HttpHeaders();
headers.set(HttpHeaders.SET_COOKIE, cookie.toString()); TestCookieAssertions(ResponseCookie cookie) {
when(response.getHeaders()).thenReturn(headers); super(new TestExchangeResult(cookie), "");
when(response.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200)); }
ExchangeResult result = new ExchangeResult(new MockClientHttpRequest(), response, null);
return new CookieAssertions(result, mock()); @Override
protected MultiValueMap<String, ResponseCookie> getResponseCookies() {
ResponseCookie cookie = getExchangeResult().cookie();
return MultiValueMap.fromSingleValue(Map.of(cookie.getName(), cookie));
}
@Override
protected void assertWithDiagnostics(Runnable assertion) {
assertion.run();
}
}
private record TestExchangeResult(ResponseCookie cookie) {
} }
} }

View File

@ -14,9 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.test.web.servlet.client; package org.springframework.test.web.support;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@ -27,21 +26,17 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.http.ContentDisposition; import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.http.client.MockClientHttpRequest;
import org.springframework.web.client.RestClient;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasItems;
import static org.mockito.BDDMockito.mock;
import static org.mockito.BDDMockito.when;
/** /**
* Tests for {@link HeaderAssertions}. * Tests for {@link AbstractHeaderAssertions}.
* *
* @author Rossen Stoyanchev
* @author Rob Worsnop * @author Rob Worsnop
*/ */
class HeaderAssertionTests { class HeaderAssertionTests {
@ -51,7 +46,7 @@ class HeaderAssertionTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar"); headers.add("foo", "bar");
headers.add("age", "22"); headers.add("age", "22");
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.valueEquals("foo", "bar"); assertions.valueEquals("foo", "bar");
@ -60,16 +55,16 @@ class HeaderAssertionTests {
assertions.valueEquals("age", 22); assertions.valueEquals("age", 22);
// Missing header // Missing header
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.valueEquals("what?!", "bar")); .isThrownBy(() -> assertions.valueEquals("what?!", "bar"));
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.valueEquals("foo", "what?!")); .isThrownBy(() -> assertions.valueEquals("foo", "what?!"));
// Wrong # of values // Wrong # of values
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.valueEquals("foo", "bar", "what?!")); .isThrownBy(() -> assertions.valueEquals("foo", "bar", "what?!"));
} }
@Test @Test
@ -77,25 +72,25 @@ class HeaderAssertionTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar"); headers.add("foo", "bar");
headers.add("foo", "baz"); headers.add("foo", "baz");
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.valueEquals("foo", "bar", "baz"); assertions.valueEquals("foo", "bar", "baz");
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.valueEquals("foo", "bar", "what?!")); .isThrownBy(() -> assertions.valueEquals("foo", "bar", "what?!"));
// Too few values // Too few values
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.valueEquals("foo", "bar")); .isThrownBy(() -> assertions.valueEquals("foo", "bar"));
} }
@Test @Test
void valueMatches() { void valueMatches() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8")); headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.valueMatches("Content-Type", ".*UTF-8.*"); assertions.valueMatches("Content-Type", ".*UTF-8.*");
@ -112,7 +107,7 @@ class HeaderAssertionTests {
void valueMatchesWithNonexistentHeader() { void valueMatchesWithNonexistentHeader() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8")); headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertThatExceptionOfType(AssertionError.class) assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.valueMatches("Content-XYZ", ".*ISO-8859-1.*")) .isThrownBy(() -> assertions.valueMatches("Content-XYZ", ".*ISO-8859-1.*"))
@ -125,7 +120,7 @@ class HeaderAssertionTests {
headers.add("foo", "value1"); headers.add("foo", "value1");
headers.add("foo", "value2"); headers.add("foo", "value2");
headers.add("foo", "value3"); headers.add("foo", "value3");
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.valuesMatch("foo", "val.*1", "val.*2", "val.*3"); assertions.valuesMatch("foo", "val.*1", "val.*2", "val.*3");
@ -145,7 +140,7 @@ class HeaderAssertionTests {
void valueMatcher() { void valueMatcher() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar"); headers.add("foo", "bar");
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.value("foo", containsString("a")); assertions.value("foo", containsString("a"));
} }
@ -155,7 +150,7 @@ class HeaderAssertionTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.add("foo", "bar"); headers.add("foo", "bar");
headers.add("foo", "baz"); headers.add("foo", "baz");
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.values("foo", hasItems("bar", "baz")); assertions.values("foo", hasItems("bar", "baz"));
} }
@ -164,14 +159,14 @@ class HeaderAssertionTests {
void exists() { void exists() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); headers.setContentType(MediaType.APPLICATION_JSON);
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.exists("Content-Type"); assertions.exists("Content-Type");
// Header should not exist // Header should not exist
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.exists("Framework")) .isThrownBy(() -> assertions.exists("Framework"))
.satisfies(ex -> assertThat(ex).hasMessage("Response header 'Framework' does not exist")); .satisfies(ex -> assertThat(ex).hasMessage("Response header 'Framework' does not exist"));
} }
@ -179,14 +174,14 @@ class HeaderAssertionTests {
void doesNotExist() { void doesNotExist() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8")); headers.setContentType(MediaType.parseMediaType("application/json;charset=UTF-8"));
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.doesNotExist("Framework"); assertions.doesNotExist("Framework");
// Existing header // Existing header
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.doesNotExist("Content-Type")) .isThrownBy(() -> assertions.doesNotExist("Content-Type"))
.satisfies(ex -> assertThat(ex).hasMessage("Response header " + .satisfies(ex -> assertThat(ex).hasMessage("Response header " +
"'Content-Type' exists with value=[application/json;charset=UTF-8]")); "'Content-Type' exists with value=[application/json;charset=UTF-8]"));
} }
@ -195,7 +190,7 @@ class HeaderAssertionTests {
void contentTypeCompatibleWith() { void contentTypeCompatibleWith() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML); headers.setContentType(MediaType.APPLICATION_XML);
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.contentTypeCompatibleWith(MediaType.parseMediaType("application/*")); assertions.contentTypeCompatibleWith(MediaType.parseMediaType("application/*"));
@ -211,14 +206,13 @@ class HeaderAssertionTests {
void location() { void location() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create("http://localhost:8080/")); headers.setLocation(URI.create("http://localhost:8080/"));
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.location("http://localhost:8080/"); assertions.location("http://localhost:8080/");
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.location("http://localhost:8081/"));
assertions.location("http://localhost:8081/"));
} }
@Test @Test
@ -227,51 +221,50 @@ class HeaderAssertionTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setCacheControl(control.getHeaderValue()); headers.setCacheControl(control.getHeaderValue());
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
// Success // Success
assertions.cacheControl(control); assertions.cacheControl(control);
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.cacheControl(CacheControl.noStore())); .isThrownBy(() -> assertions.cacheControl(CacheControl.noStore()));
} }
@Test @Test
void contentDisposition() { void contentDisposition() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("foo", "bar"); headers.setContentDispositionFormData("foo", "bar");
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.contentDisposition(ContentDisposition.formData().name("foo").filename("bar").build()); assertions.contentDisposition(ContentDisposition.formData().name("foo").filename("bar").build());
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.contentDisposition(ContentDisposition.attachment().build())); .isThrownBy(() -> assertions.contentDisposition(ContentDisposition.attachment().build()));
} }
@Test @Test
void contentLength() { void contentLength() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentLength(100); headers.setContentLength(100);
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.contentLength(100); assertions.contentLength(100);
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.contentLength(200));
assertions.contentLength(200));
} }
@Test @Test
void contentType() { void contentType() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); headers.setContentType(MediaType.APPLICATION_JSON);
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.contentType(MediaType.APPLICATION_JSON); assertions.contentType(MediaType.APPLICATION_JSON);
assertions.contentType("application/json"); assertions.contentType("application/json");
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.contentType(MediaType.APPLICATION_XML)); .isThrownBy(() -> assertions.contentType(MediaType.APPLICATION_XML));
} }
@ -280,12 +273,12 @@ class HeaderAssertionTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
ZonedDateTime expires = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); ZonedDateTime expires = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"));
headers.setExpires(expires); headers.setExpires(expires);
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.expires(expires.toInstant().toEpochMilli()); assertions.expires(expires.toInstant().toEpochMilli());
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.expires(expires.toInstant().toEpochMilli() + 1)); .isThrownBy(() -> assertions.expires(expires.toInstant().toEpochMilli() + 1));
} }
@Test @Test
@ -293,37 +286,45 @@ class HeaderAssertionTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
ZonedDateTime lastModified = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); ZonedDateTime lastModified = ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"));
headers.setLastModified(lastModified.toInstant().toEpochMilli()); headers.setLastModified(lastModified.toInstant().toEpochMilli());
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.lastModified(lastModified.toInstant().toEpochMilli()); assertions.lastModified(lastModified.toInstant().toEpochMilli());
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.lastModified(lastModified.toInstant().toEpochMilli() + 1)); .isThrownBy(() -> assertions.lastModified(lastModified.toInstant().toEpochMilli() + 1));
} }
@Test @Test
void equalsDate() { void equalsDate() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setDate("foo", 1000); headers.setDate("foo", 1000);
HeaderAssertions assertions = headerAssertions(headers); TestHeaderAssertions assertions = new TestHeaderAssertions(headers);
assertions.valueEqualsDate("foo", 1000); assertions.valueEqualsDate("foo", 1000);
// Wrong value // Wrong value
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThatExceptionOfType(AssertionError.class)
assertions.valueEqualsDate("foo", 2000)); .isThrownBy(() -> assertions.valueEqualsDate("foo", 2000));
} }
private HeaderAssertions headerAssertions(HttpHeaders responseHeaders) {
try { private static class TestHeaderAssertions extends AbstractHeaderAssertions<TestExchangeResult, Object> {
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response = mock();
when(response.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200)); TestHeaderAssertions(HttpHeaders headers) {
when(response.getHeaders()).thenReturn(responseHeaders); super(new TestExchangeResult(headers), "");
ExchangeResult result = new ExchangeResult(new MockClientHttpRequest(), response, null);
return new HeaderAssertions(result, mock());
} }
catch (IOException ex) {
throw new IllegalStateException(ex); @Override
protected HttpHeaders getResponseHeaders() {
return getExchangeResult().headers();
}
@Override
protected void assertWithDiagnostics(Runnable assertion) {
assertion.run();
} }
} }
private record TestExchangeResult(HttpHeaders headers) {}
} }

View File

@ -0,0 +1,280 @@
/*
* Copyright 2002-present 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.support;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
/**
* Tests for {@link AbstractStatusAssertions}.
*
* @author Rossen Stoyanchev
* @author Rob Worsnop
*/
class StatusAssertionTests {
@Test
void isEqualTo() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.CONFLICT);
// Success
assertions.isEqualTo(HttpStatus.CONFLICT);
assertions.isEqualTo(409);
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.isEqualTo(HttpStatus.REQUEST_TIMEOUT));
// Wrong status value
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertions.isEqualTo(408));
}
@Test
void isEqualToWithCustomStatus() {
TestStatusAssertions assertions = new TestStatusAssertions(600);
// Success
assertions.isEqualTo(600);
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(601).isEqualTo(600));
}
@Test
void reasonEquals() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.CONFLICT);
// Success
assertions.reasonEquals("Conflict");
// Wrong reason
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).reasonEquals("Conflict"));
}
@Test
void statusSeries1xx() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.CONTINUE);
// Success
assertions.is1xxInformational();
// Wrong series
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.OK).is1xxInformational());
}
@Test
void statusSeries2xx() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.OK);
// Success
assertions.is2xxSuccessful();
// Wrong series
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).is2xxSuccessful());
}
@Test
void statusSeries3xx() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.PERMANENT_REDIRECT);
// Success
assertions.is3xxRedirection();
// Wrong series
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).is3xxRedirection());
}
@Test
void statusSeries4xx() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.BAD_REQUEST);
// Success
assertions.is4xxClientError();
// Wrong series
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).is4xxClientError());
}
@Test
void statusSeries5xx() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR);
// Success
assertions.is5xxServerError();
// Wrong series
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.OK).is5xxServerError());
}
@Test
void matchesStatusValue() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.CONFLICT);
// Success
assertions.value(equalTo(409));
assertions.value(greaterThan(400));
// Wrong status
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.value(equalTo(200)));
}
@Test
void matchesCustomStatusValue() {
new TestStatusAssertions(600).value(equalTo(600));
}
@Test
void consumesStatusValue() {
TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.CONFLICT);
// Success
assertions.value((Integer value) -> assertThat(value).isEqualTo(409));
}
@Test
void statusIsAccepted() {
// Success
new TestStatusAssertions(HttpStatus.ACCEPTED).isAccepted();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isAccepted());
}
@Test
void statusIsNoContent() {
// Success
new TestStatusAssertions(HttpStatus.NO_CONTENT).isNoContent();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isNoContent());
}
@Test
void statusIsFound() {
// Success
new TestStatusAssertions(HttpStatus.FOUND).isFound();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isFound());
}
@Test
void statusIsSeeOther() {
// Success
new TestStatusAssertions(HttpStatus.SEE_OTHER).isSeeOther();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isSeeOther());
}
@Test
void statusIsNotModified() {
// Success
new TestStatusAssertions(HttpStatus.NOT_MODIFIED).isNotModified();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isNotModified());
}
@Test
void statusIsTemporaryRedirect() {
// Success
new TestStatusAssertions(HttpStatus.TEMPORARY_REDIRECT).isTemporaryRedirect();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isTemporaryRedirect());
}
@Test
void statusIsPermanentRedirect() {
// Success
new TestStatusAssertions(HttpStatus.PERMANENT_REDIRECT).isPermanentRedirect();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isPermanentRedirect());
}
@Test
void statusIsUnauthorized() {
// Success
new TestStatusAssertions(HttpStatus.UNAUTHORIZED).isUnauthorized();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isUnauthorized());
}
@Test
void statusIsForbidden() {
// Success
new TestStatusAssertions(HttpStatus.FORBIDDEN).isForbidden();
// Wrong status
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> new TestStatusAssertions(HttpStatus.INTERNAL_SERVER_ERROR).isForbidden());
}
private static class TestStatusAssertions extends AbstractStatusAssertions<TestExchangeResult, Object> {
TestStatusAssertions(HttpStatus status) {
this(status.value());
}
TestStatusAssertions(int status) {
super(new TestExchangeResult(HttpStatusCode.valueOf(status)), "");
}
@Override
protected HttpStatusCode getStatus() {
return getExchangeResult().status();
}
@Override
protected void assertWithDiagnostics(Runnable assertion) {
assertion.run();
}
}
private record TestExchangeResult(HttpStatusCode status) {
}
}

View File

@ -98,7 +98,7 @@
<suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]context[\\/]aot[\\/]samples[\\/]web[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/> <suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]context[\\/]aot[\\/]samples[\\/]web[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/>
<suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]context[\\/]junit[\\/]jupiter[\\/]web[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/> <suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]context[\\/]junit[\\/]jupiter[\\/]web[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/>
<suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]util[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/> <suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]util[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/>
<suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]web[\\/](client|reactive|servlet)[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/> <suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]web[\\/](client|reactive|servlet|support)[\\/].+Tests" checks="IllegalImport" id="bannedHamcrestImports"/>
<suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]context[\\/](aot|junit4)" checks="SpringJUnit5"/> <suppress files="src[\\/]test[\\/]java[\\/]org[\\/]springframework[\\/]test[\\/]context[\\/](aot|junit4)" checks="SpringJUnit5"/>
<suppress files="org[\\/]springframework[\\/]test[\\/]context[\\/].+[\\/](ExpectedExceptionSpringRunnerTests|StandardJUnit4FeaturesTests|ProgrammaticTxMgmtTestNGTests)" checks="RegexpSinglelineJava" id="expectedExceptionAnnotation"/> <suppress files="org[\\/]springframework[\\/]test[\\/]context[\\/].+[\\/](ExpectedExceptionSpringRunnerTests|StandardJUnit4FeaturesTests|ProgrammaticTxMgmtTestNGTests)" checks="RegexpSinglelineJava" id="expectedExceptionAnnotation"/>