From 68463e2018eed926b7a9d1aaba7fe4215c51c0fd Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 13 Mar 2018 15:55:39 +0100 Subject: [PATCH] Support target type in JsonPath assertions for MockMvc results This commit picks up where SPR-14498 left off by adding support for an explicit target type when using JsonPath to perform an assertion against the response content using a Hamcrest Matcher. Specifically, there is a new overloaded value(Matcher, Class) method in JsonPathResultMatchers for use with Hamcrest matchers where the target type (i.e., Class) can be specified. Issue: SPR-16587 --- .../test/util/JsonPathExpectationsHelper.java | 10 +++---- .../client/match/JsonPathRequestMatchers.java | 12 +++++---- .../client/match/MockRestRequestMatchers.java | 2 +- .../result/JsonPathResultMatchers.java | 26 ++++++++++++++++++- .../servlet/result/MockMvcResultMatchers.java | 4 +-- .../match/JsonPathRequestMatchersTests.java | 22 +++++++++++----- .../result/JsonPathResultMatchersTests.java | 22 +++++++++++----- 7 files changed, 72 insertions(+), 26 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java index f6b44fdaeb5..a101b25a670 100644 --- a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -237,22 +237,22 @@ public class JsonPathExpectationsHelper { } private Object evaluateJsonPath(String content) { - String message = "No value at JSON path \"" + this.expression + "\", exception: "; try { return this.jsonPath.read(content); } catch (Throwable ex) { - throw new AssertionError(message + ex.getMessage()); + String message = "No value at JSON path \"" + this.expression + "\""; + throw new AssertionError(message, ex); } } private Object evaluateJsonPath(String content, Class targetType) { - String message = "No value at JSON path \"" + this.expression + "\", exception: "; try { return JsonPath.parse(content).read(this.expression, targetType); } catch (Throwable ex) { - throw new AssertionError(message + ex.getMessage()); + String message = "No value at JSON path \"" + this.expression + "\""; + throw new AssertionError(message, ex); } } diff --git a/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java b/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java index f308ddc796d..4c8e3828794 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -30,6 +30,7 @@ import org.springframework.test.web.client.RequestMatcher; /** * Factory for assertions on the request content using * JsonPath expressions. + * *

An instance of this class is typically accessed via * {@link MockRestRequestMatchers#jsonPath(String, Matcher)} or * {@link MockRestRequestMatchers#jsonPath(String, Object...)}. @@ -70,10 +71,11 @@ public class JsonPathRequestMatchers { } /** - * An overloaded variant of (@link {@link #value(Matcher)} that also - * accepts a target type for the resulting value that the matcher can work - * reliably against. This can be useful for matching numbers reliably for - * example coercing an integer into a double. + * An overloaded variant of {@link #value(Matcher)} that also accepts a + * target type for the resulting value that the matcher can work reliably + * against. + *

This can be useful for matching numbers reliably — for example, + * to coerce an integer into a double. * @since 4.3.3 */ public RequestMatcher value(final Matcher matcher, final Class targetType) { diff --git a/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java b/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java index de2a4942d79..ff7e25ef81c 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/match/MockRestRequestMatchers.java @@ -219,7 +219,7 @@ public abstract class MockRestRequestMatchers { * @param expression the JSON path optionally parameterized with arguments * @param args arguments to parameterize the JSON path expression with */ - public static JsonPathRequestMatchers jsonPath(String expression, Object ... args) { + public static JsonPathRequestMatchers jsonPath(String expression, Object... args) { return new JsonPathRequestMatchers(expression, args); } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java index fe33f1073d8..efa3c1f0105 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -78,6 +78,8 @@ public class JsonPathResultMatchers { /** * Evaluate the JSON path expression against the response content and * assert the resulting value with the given Hamcrest {@link Matcher}. + * @see #value(Matcher, Class) + * @see #value(Object) */ public ResultMatcher value(final Matcher matcher) { return new ResultMatcher() { @@ -89,9 +91,31 @@ public class JsonPathResultMatchers { }; } + /** + * An overloaded variant of {@link #value(Matcher)} that also accepts a + * target type for the resulting value that the matcher can work reliably + * against. + *

This can be useful for matching numbers reliably — for example, + * to coerce an integer into a double. + * @since 4.3.15 + * @see #value(Matcher) + * @see #value(Object) + */ + public ResultMatcher value(Matcher matcher, Class targetType) { + return new ResultMatcher() { + @Override + public void match(MvcResult result) throws Exception { + String content = getContent(result); + jsonPathHelper.assertValue(content, matcher, targetType); + } + }; + } + /** * Evaluate the JSON path expression against the response content and * assert that the result is equal to the supplied value. + * @see #value(Matcher) + * @see #value(Matcher, Class) */ public ResultMatcher value(final Object expectedValue) { return new ResultMatcher() { diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java index a12baf949f5..d90c775f982 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/MockMvcResultMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -176,7 +176,7 @@ public abstract class MockMvcResultMatchers { * @param expression the JSON path expression, optionally parameterized with arguments * @param args arguments to parameterize the JSON path expression with */ - public static JsonPathResultMatchers jsonPath(String expression, Object ... args) { + public static JsonPathResultMatchers jsonPath(String expression, Object... args) { return new JsonPathResultMatchers(expression, args); } diff --git a/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java b/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java index 0b2069b19fb..1b55c7b3df9 100644 --- a/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 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. @@ -55,14 +55,19 @@ public class JsonPathRequestMatchersTests { } + @Test(expected = AssertionError.class) + public void valueWithMismatch() throws Exception { + new JsonPathRequestMatchers("$.str").value("bogus").match(request); + } + @Test - public void value() throws Exception { + public void valueWithDirectMatch() throws Exception { new JsonPathRequestMatchers("$.str").value("foo").match(request); } - @Test(expected = AssertionError.class) - public void valueNoMatch() throws Exception { - new JsonPathRequestMatchers("$.str").value("bogus").match(request); + @Test // SPR-14498 + public void valueWithNumberConversion() throws Exception { + new JsonPathRequestMatchers("$.num").value(5.0f).match(request); } @Test @@ -70,8 +75,13 @@ public class JsonPathRequestMatchersTests { new JsonPathRequestMatchers("$.str").value(equalTo("foo")).match(request); } + @Test // SPR-14498 + public void valueWithMatcherAndNumberConversion() throws Exception { + new JsonPathRequestMatchers("$.num").value(equalTo(5.0f), Float.class).match(request); + } + @Test(expected = AssertionError.class) - public void valueWithMatcherNoMatch() throws Exception { + public void valueWithMatcherAndMismatch() throws Exception { new JsonPathRequestMatchers("$.str").value(equalTo("bogus")).match(request); } diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java index b587a34e5c2..832981c7ca3 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -58,14 +58,19 @@ public class JsonPathResultMatchersTests { } } + @Test(expected = AssertionError.class) + public void valueWithMismatch() throws Exception { + new JsonPathResultMatchers("$.str").value("bogus").match(stubMvcResult); + } + @Test - public void value() throws Exception { + public void valueWithDirectMatch() throws Exception { new JsonPathResultMatchers("$.str").value("foo").match(stubMvcResult); } - @Test(expected = AssertionError.class) - public void valueNoMatch() throws Exception { - new JsonPathResultMatchers("$.str").value("bogus").match(stubMvcResult); + @Test // SPR-16587 + public void valueWithNumberConversion() throws Exception { + new JsonPathResultMatchers("$.num").value(5.0f).match(stubMvcResult); } @Test @@ -73,8 +78,13 @@ public class JsonPathResultMatchersTests { new JsonPathResultMatchers("$.str").value(Matchers.equalTo("foo")).match(stubMvcResult); } + @Test // SPR-16587 + public void valueWithMatcherAndNumberConversion() throws Exception { + new JsonPathResultMatchers("$.num").value(Matchers.equalTo(5.0f), Float.class).match(stubMvcResult); + } + @Test(expected = AssertionError.class) - public void valueWithMatcherNoMatch() throws Exception { + public void valueWithMatcherAndMismatch() throws Exception { new JsonPathResultMatchers("$.str").value(Matchers.equalTo("bogus")).match(stubMvcResult); }