001/* 002 * Copyright 2002-2019 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.assertThat; 033import static org.springframework.test.util.AssertionErrors.assertEquals; 034import static org.springframework.test.util.AssertionErrors.assertNotNull; 035import static org.springframework.test.util.AssertionErrors.assertTrue; 036import static org.springframework.test.util.AssertionErrors.fail; 037 038/** 039 * Factory for assertions on the selected handler or handler method. 040 * 041 * <p>An instance of this class is typically accessed via 042 * {@link MockMvcResultMatchers#handler}. 043 * 044 * <p><strong>Note:</strong> Expectations that assert the controller method 045 * used to process the request work only for requests processed with 046 * {@link RequestMappingHandlerMapping} and {@link RequestMappingHandlerAdapter} 047 * which is used by default with the Spring MVC Java config and XML namespace. 048 * 049 * @author Rossen Stoyanchev 050 * @author Sam Brannen 051 * @since 3.2 052 */ 053public class HandlerResultMatchers { 054 055 /** 056 * Protected constructor. 057 * Use {@link MockMvcResultMatchers#handler()}. 058 */ 059 protected HandlerResultMatchers() { 060 } 061 062 063 /** 064 * Assert the type of the handler that processed the request. 065 */ 066 public ResultMatcher handlerType(Class<?> type) { 067 return result -> { 068 Object handler = result.getHandler(); 069 assertNotNull("No handler", handler); 070 if (handler != null) { 071 Class<?> actual = handler.getClass(); 072 if (HandlerMethod.class.isInstance(handler)) { 073 actual = ((HandlerMethod) handler).getBeanType(); 074 } 075 assertEquals("Handler type", type, ClassUtils.getUserClass(actual)); 076 } 077 }; 078 } 079 080 /** 081 * Assert the controller method used to process the request. 082 * <p>The expected method is specified through a "mock" controller method 083 * invocation similar to {@link MvcUriComponentsBuilder#fromMethodCall(Object)}. 084 * <p>For example, given this controller: 085 * <pre class="code"> 086 * @RestController 087 * public class SimpleController { 088 * 089 * @RequestMapping("/") 090 * public ResponseEntity<Void> handle() { 091 * return ResponseEntity.ok().build(); 092 * } 093 * } 094 * </pre> 095 * <p>A test that has statically imported {@link MvcUriComponentsBuilder#on} 096 * can be performed as follows: 097 * <pre class="code"> 098 * mockMvc.perform(get("/")) 099 * .andExpect(handler().methodCall(on(SimpleController.class).handle())); 100 * </pre> 101 * @param obj either the value returned from a "mock" controller invocation 102 * or the "mock" controller itself after an invocation 103 */ 104 public ResultMatcher methodCall(Object obj) { 105 return result -> { 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 * Assert the name of the controller method used to process the request 120 * using the given Hamcrest {@link Matcher}. 121 */ 122 public ResultMatcher methodName(Matcher<? super String> matcher) { 123 return result -> { 124 HandlerMethod handlerMethod = getHandlerMethod(result); 125 assertThat("Handler method", handlerMethod.getMethod().getName(), matcher); 126 }; 127 } 128 129 /** 130 * Assert the name of the controller method used to process the request. 131 */ 132 public ResultMatcher methodName(String name) { 133 return result -> { 134 HandlerMethod handlerMethod = getHandlerMethod(result); 135 assertEquals("Handler method", name, handlerMethod.getMethod().getName()); 136 }; 137 } 138 139 /** 140 * Assert the controller method used to process the request. 141 */ 142 public ResultMatcher method(Method method) { 143 return result -> { 144 HandlerMethod handlerMethod = getHandlerMethod(result); 145 assertEquals("Handler method", method, handlerMethod.getMethod()); 146 }; 147 } 148 149 150 private static HandlerMethod getHandlerMethod(MvcResult result) { 151 Object handler = result.getHandler(); 152 assertTrue("Not a HandlerMethod: " + handler, handler instanceof HandlerMethod); 153 return (HandlerMethod) handler; 154 } 155 156}