[SPRING] Spring : @Aspect 주석으로 주석 된 클래스에 모의 삽입을 할 수 없다.
SPRINGSpring : @Aspect 주석으로 주석 된 클래스에 모의 삽입을 할 수 없다.
AspectJ를 사용하여 Before advice를 만들었다.
package test.accesscontrol.permissionchecker;
import test.accesscontrol.database.SessionExpiredException;
import test.database.UsersDatabaseAccessProvider;
import test.common.constants.GlobalConstants;
import test.common.model.AbstractRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
@Aspect
public class ValidSessionChecker {
private static final int REQUEST_PARAMETER_ARGUMENT_POSITION = GlobalConstants.ZERO;
private UsersDatabaseAccessProvider usersDatabaseAccessProvider;
@Autowired
public ValidSessionChecker(UsersDatabaseAccessProvider usersDatabaseAccessProvider) {
this.usersDatabaseAccessProvider = usersDatabaseAccessProvider;
}
@Before("@annotation(test.accesscontrol.permissionchecker.ValidSessionRequired)")
public void before(JoinPoint joinPoint) throws Throwable {
Object requestParameterObject = joinPoint.getArgs()[REQUEST_PARAMETER_ARGUMENT_POSITION];
AbstractRequest requestParameter = (AbstractRequest) requestParameterObject;
String sessionID = requestParameter.getSessionId();
if(!usersDatabaseAccessProvider.sessionNotExpired(sessionID))
throw new SessionExpiredException(String.format("Session expired: %s", sessionID));
}
}
및 테스트 클래스 :
package test.accesscontrol;
import test.accesscontrol.database.UsersDatabaseAccessProvider;
import test.accesscontrol.permissionchecker.ValidSessionChecker;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml")
public class AccessControlControllerTestsWithInjectedMocks {
@Autowired
private org.springframework.web.context.WebApplicationContext wac;
private MockMvc mockMvc;
@Mock
UsersDatabaseAccessProvider usersDatabaseAccessProvider;
@InjectMocks
ValidSessionChecker validSessionChecker;
@InjectMocks
AccessControlController accessControlController;
@Before
public void before() throws Throwable {
//given
MockitoAnnotations.initMocks(this);
when(usersDatabaseAccessProvider.sessionNotExpired("123456")).thenReturn(Boolean.FALSE);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void changePassword_shouldReturnUnauthorizedHttpCodeWhenSessionIsExpired() throws Exception {
//when
ResultActions results = mockMvc.perform(
post("/accesscontrol/changePassword")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"sessionId\":\"123456\", \"oldPassword\":\"password\", \"newPassword\":\"newPassword\"}")
);
//then
results.andExpect(status().isUnauthorized());
verify(usersDatabaseAccessProvider, never()).getSessionOwner(anyString());
verify(usersDatabaseAccessProvider, never()).isCurrentPasswordValid(anyString(), anyString());
verify(usersDatabaseAccessProvider, never()).setNewPassword(anyString(), anyString());
}
}
스프링 구성 파일 :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<mvc:annotation-driven />
<aop:aspectj-autoproxy />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean class="org.springframework.context.support.ResourceBundleMessageSource"
id="messageSource">
<property name="basename" value="messages" />
</bean>
<bean id="usersDatabaseAccessProvider" class="test.accesscontrol.database.UsersDatabaseAccessProvider"/>
<bean id="accessControlController" class="test.accesscontrol.AccessControlController">
<property name="sessionExpirationTimeInSeconds" value="600"/>
</bean>
<bean id="validSessionChecker" class="test.accesscontrol.permissionchecker.ValidSessionChecker" />
<bean id="timeDispatcher" class="test.utils.time.TimeDispatcher" scope="singleton" />
</beans>
액세스 제어 컨트롤러
@Controller
@RequestMapping("/accesscontrol")
public class AccessControlController {
...
@RequestMapping(value = "changePassword", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE)
@ValidSessionRequired
public ResponseEntity<Void> changePassword(@Valid @RequestBody ChangePasswordRequest request) throws OperationForbiddenException {
String sessionId = request.getSessionId();
String userEmailAddress = usersDatabaseAccessProvider.getSessionOwner(sessionId);
String currentPassword = request.getOldPassword();
this.ensureThatCurrentPasswordIsValid(userEmailAddress, currentPassword);
usersDatabaseAccessProvider.setNewPassword(userEmailAddress, request.getNewPassword());
return new ResponseEntity<Void>(HttpStatus.OK);
}
@ExceptionHandler({SessionExpiredException.class})
public ResponseEntity<Void> handleSessionExpiredException(Exception ex) {
return new ResponseEntity<Void>(HttpStatus.UNAUTHORIZED);
}
}
mockMvc.perform (...)을 호출하면 메서드를 가로 채고 예외를 throw하고 401 Unauthorized 코드를 반환해야합니다.
물론 작동하지 않습니다. 테스트를 디버그하려고 시도했습니다.
UsersDatabaseAccessProvider의 조롱 된 인스턴스를 ValidSessionChecker에 삽입하려면 어떻게해야합니까?
해결법
-
==============================
1.여기서 문제는 Mock 인스턴스와 ValidSessionChecker가 Spring 빈이 아니므로 Spring에서 관리하는 ValidSessionChecker에 연결되어 있지 않다는 것입니다. mock을 만들기 위해서 스프링 빈은 아마도 기본 설정 파일에 정의 된 bean을 확장하고 mock을 추가하는 또 다른 bean 정의 파일을 만드는 것이 더 나은 방법 일 것이다.
여기서 문제는 Mock 인스턴스와 ValidSessionChecker가 Spring 빈이 아니므로 Spring에서 관리하는 ValidSessionChecker에 연결되어 있지 않다는 것입니다. mock을 만들기 위해서 스프링 빈은 아마도 기본 설정 파일에 정의 된 bean을 확장하고 mock을 추가하는 또 다른 bean 정의 파일을 만드는 것이 더 나은 방법 일 것이다.
test-config.xml :
<beans...> <import resource="base-springmvc-config.xml"/> <beans:bean name="usersDatabaseAccessProvider" factory-method="mock" class="org.mockito.Mockito"> <beans:constructor-arg value="..UsersDatabaseAccessProvider"></beans:constructor-arg> </beans:bean>
그리고 나서 테스트에서 모의 행위에 행동을 주입하십시오 :
public class AccessControlControllerTestsWithInjectedMocks { @Autowired private org.springframework.web.context.WebApplicationContext wac; private MockMvc mockMvc; @Autowired UsersDatabaseAccessProvider usersDatabaseAccessProvider; @Autowired ValidSessionChecker validSessionChecker; .... @Before public void before() throws Throwable { //given MockitoAnnotations.initMocks(this); when(usersDatabaseAccessProvider.sessionNotExpired("123456")).thenReturn(Boolean.FALSE); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); }
이것은 깔끔하게 작동해야합니다.
from https://stackoverflow.com/questions/17624341/spring-cannot-inject-a-mock-into-class-annotated-with-the-aspect-annotation by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring - JPA - 작업을 읽지 만 계속 유지합니다. 사용할 수있는 트랜잭션 EntityManager가 없습니다. 왜? (0) | 2019.05.14 |
---|---|
[SPRING] sql prepared statement, spring, SimpleJDBCTemplate에서 LIKE 절 사용 (0) | 2019.05.14 |
[SPRING] 카프카에서 여러 번 같은 메시지 읽기 (0) | 2019.05.14 |
[SPRING] @ConfigurationProperties를 @Configuration에 autowire하는 방법은 무엇입니까? (0) | 2019.05.14 |
[SPRING] JUnit 테스트 케이스는 eclipse와 함께 전달되지만 maven 빌드에서는 실패합니다. (0) | 2019.05.14 |