001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.test.web.servlet.result;
018
019import java.lang.reflect.Method;
020
021import org.hamcrest.Matcher;
022
023import org.springframework.test.web.servlet.MvcResult;
024import org.springframework.test.web.servlet.ResultMatcher;
025import org.springframework.util.ClassUtils;
026import org.springframework.web.method.HandlerMethod;
027import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
028import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder.MethodInvocationInfo;
029import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
030import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
031
032import static org.hamcrest.MatcherAssert.*;
033import static org.springframework.test.util.AssertionErrors.*;
034
035/**
036 * Factory for assertions on the selected handler or handler method.
037 *
038 * <p>An instance of this class is typically accessed via
039 * {@link MockMvcResultMatchers#handler}.
040 *
041 * <p><strong>Note:</strong> Expectations that assert the controller method
042 * used to process the request work only for requests processed with
043 * {@link RequestMappingHandlerMapping} and {@link RequestMappingHandlerAdapter}
044 * which is used by default with the Spring MVC Java config and XML namespace.
045 *
046 * @author Rossen Stoyanchev
047 * @author Sam Brannen
048 * @since 3.2
049 */
050public class HandlerResultMatchers {
051
052        /**
053         * Protected constructor.
054         * Use {@link MockMvcResultMatchers#handler()}.
055         */
056        protected HandlerResultMatchers() {
057        }
058
059
060        /**
061         * Assert the type of the handler that processed the request.
062         */
063        public ResultMatcher handlerType(final Class<?> type) {
064                return new ResultMatcher() {
065                        @Override
066                        public void match(MvcResult result) throws Exception {
067                                Object handler = result.getHandler();
068                                assertTrue("No handler", handler != null);
069                                Class<?> actual = handler.getClass();
070                                if (HandlerMethod.class.isInstance(handler)) {
071                                        actual = ((HandlerMethod) handler).getBeanType();
072                                }
073                                assertEquals("Handler type", type, ClassUtils.getUserClass(actual));
074                        }
075                };
076        }
077
078        /**
079         * Assert the controller method used to process the request.
080         * <p>The expected method is specified through a "mock" controller method
081         * invocation similar to {@link MvcUriComponentsBuilder#fromMethodCall(Object)}.
082         * <p>For example, given this controller:
083         * <pre class="code">
084         * &#064;RestController
085         * public class SimpleController {
086         *
087         *     &#064;RequestMapping("/")
088         *     public ResponseEntity<Void> handle() {
089         *         return ResponseEntity.ok().build();
090         *     }
091         * }
092         * </pre>
093         * <p>A test that has statically imported {@link MvcUriComponentsBuilder#on}
094         * can be performed as follows:
095         * <pre class="code">
096         * mockMvc.perform(get("/"))
097         *     .andExpect(handler().methodCall(on(SimpleController.class).handle()));
098         * </pre>
099         * @param obj either the value returned from a "mock" controller invocation
100         * or the "mock" controller itself after an invocation
101         */
102        public ResultMatcher methodCall(final Object obj) {
103                return new ResultMatcher() {
104                        @Override
105                        public void match(MvcResult result) throws Exception {
106                                if (!(obj instanceof MethodInvocationInfo)) {
107                                        fail(String.format("The supplied object [%s] is not an instance of %s. " +
108                                                        "Ensure that you invoke the handler method via MvcUriComponentsBuilder.on().",
109                                                        obj, MethodInvocationInfo.class.getName()));
110                                }
111                                MethodInvocationInfo invocationInfo = (MethodInvocationInfo) obj;
112                                Method expected = invocationInfo.getControllerMethod();
113                                Method actual = getHandlerMethod(result).getMethod();
114                                assertEquals("Handler method", expected, actual);
115                        }
116                };
117        }
118
119        /**
120         * Assert the name of the controller method used to process the request
121         * using the given Hamcrest {@link Matcher}.
122         */
123        public ResultMatcher methodName(final Matcher<? super String> matcher) {
124                return new ResultMatcher() {
125                        @Override
126                        public void match(MvcResult result) throws Exception {
127                                HandlerMethod handlerMethod = getHandlerMethod(result);
128                                assertThat("Handler method", handlerMethod.getMethod().getName(), matcher);
129                        }
130                };
131        }
132
133        /**
134         * Assert the name of the controller method used to process the request.
135         */
136        public ResultMatcher methodName(final String name) {
137                return new ResultMatcher() {
138                        @Override
139                        public void match(MvcResult result) throws Exception {
140                                HandlerMethod handlerMethod = getHandlerMethod(result);
141                                assertEquals("Handler method", name, handlerMethod.getMethod().getName());
142                        }
143                };
144        }
145
146        /**
147         * Assert the controller method used to process the request.
148         */
149        public ResultMatcher method(final Method method) {
150                return new ResultMatcher() {
151                        @Override
152                        public void match(MvcResult result) throws Exception {
153                                HandlerMethod handlerMethod = getHandlerMethod(result);
154                                assertEquals("Handler method", method, handlerMethod.getMethod());
155                        }
156                };
157        }
158
159
160        private static HandlerMethod getHandlerMethod(MvcResult result) {
161                Object handler = result.getHandler();
162                assertTrue("No handler: ", handler != null);
163                assertTrue("Not a HandlerMethod: " + handler, HandlerMethod.class.isInstance(handler));
164                return (HandlerMethod) handler;
165        }
166
167}