-
Notifications
You must be signed in to change notification settings - Fork 1
Closed
Description
클래스 필터를 사용하여 프록시 자동생성을 시도해 보았습니다.
481 ~ 486p에 따라 코드를 수정하고 테스트를 진행하였는데, UserServiceTest가 실패하였습니다.
코드 상 실수나 접근이 잘 못되었는지 확인 부탁드립니다.
실패한 테스트는 upgradeLevels와 upgradeAllOrNothing입니다.
upgradeLevels 실패
우선 483p에서 userServiceImpl의 빈의 아이디를 userService로 바꾸어 주었습니다.
<!-- 이제 다시 userService 아이디를 사용할 수 있다. -->
<bean id = "userService" class="com.taxol.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<property name="mailSender" ref="mailSender"/>
</bean>이에따라 기존의 UserServiceImpl는 DI를 할 수 없어 제거하였습니다.
@Autowired
UserServiceImpl userServiceImpl; // 제거하였음이는 UserServiceTest의 upgradeLevels 메서드에서 오류가 나는데,
기존의 코드는
@Test
@DirtiesContext
public void upgradeLevels() {
userDao.deleteAll();
for(User user : users) userDao.add(user);
// 메일 발송 결과를 테스트할 수 있도록 목 오브젝트를 만들어 userService의 의존 오브젝트로 주입한다.
MockMailSender mockMailSender = new MockMailSender();
userServiceImpl.setMailSender(mockMailSender);
userService.upgradeLevels();
// 각 사용자별로 업그레이드 후의 예상 레벨을 검증한다.
checkLevelUpgraded(users.get(0), false);
checkLevelUpgraded(users.get(1), true);
checkLevelUpgraded(users.get(2), false);
checkLevelUpgraded(users.get(3), true);
checkLevelUpgraded(users.get(4), false);
// 목 오브젝트에 저장된 메일 수신자 목록을 가져와 업그레이드 대상과 일치하는지 확인 한다.
List<String> request = mockMailSender.getRequests();
assertThat(request.size(), is(2));
assertThat(request.get(0), is(users.get(1).getEmail()));
assertThat(request.get(1), is(users.get(3).getEmail()));
}와 같습니다.
여기서 userServiceImpl.setMailSender(mockMailSender);가 오류가 나, 이 코드를 제거하였더니 결과가
java.long.AssertionError:
Expectd: is <2>
but wsas <0>
으로 제대로 동작하질 않습니다.
upgradeAllOrNothing 실패
upgradeAllOrNothing의 코드의
fail("TestUserService Exception expected");
을 통해 실패하였습니다.
아예 this.testUserService.upgradeLevels(); 코드가 실패하였다고 생각합니다.
전체 코드
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="connectionMaker" class="com.taxol.chapter1_8.DConnectionMaker" /> -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/tobyspring?useSSL=false"/>
<property name="username" value="ssafy"/>
<property name="password" value="ssafy"/>
</bean>
<bean id="userDao" class="com.taxol.dao.UserDaoJdbc">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 이제 userService는 userServiceTx의 오브젝트가 주입 된다. -->
<!-- <bean id="userService" class ="com.taxol.service.UserServiceTx">
<property name="transactionManager" ref="transactionManager"></property>
<property name="userService" ref="userServiceImpl"></property>
</bean> -->
<!-- UserService에 대한 트랜잭션 프록시 팩토리 빈 -->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userServiceImpl" />
<property name="interceptorNames">
<list>
<value>transactionAdvisor</value>
</list>
</property>
</bean>
<bean id = "userServiceImpl" class="com.taxol.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<property name="mailSender" ref="mailSender"/>
</bean>
<bean id = "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref = "dataSource"></property>
</bean>
<bean id="mailSender" class = "com.taxol.service.DummyMailSender"/>
<!-- 어드바이스 -->
<bean id ="transactionAdvice" class="com.taxol.service.TransactionAdvice">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 스프링이 제공하는 포인트컷 클래스 사용 -->
<bean id ="transactionPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="upgrade*"/>
</bean>
<!-- 어드바이저 -->
<bean id ="transactionAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="transactionAdvice"/>
<property name="pointcut" ref="transactionPointcut"/>
</bean>
</beans>UserServiceTest
package com.taxol.proxy;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import javax.sql.DataSource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import com.taxol.dao.UserDao;
import com.taxol.domain.Level;
import com.taxol.domain.User;
import com.taxol.service.DummyMailSender;
import com.taxol.service.MockMailSender;
import com.taxol.service.TransactionHandler;
import com.taxol.service.UserService;
import com.taxol.service.UserServiceImpl;
import com.taxol.service.UserServiceTx;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationcontext.xml")
public class UserServiceTest {
private static final int MIN_LOGCOUNT_FOR_SIVER = 50;
private static final int MIN_RECOMMEND_FOR_GOLD = 30;
@Autowired
UserService userService;
@Autowired
UserService testUserService;
@Autowired
UserDao userDao;
List<User> users; // 테스트 픽스처
@Autowired
private DataSource dataSource;
@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
MailSender mailSender;
@Before
public void setUp() throws Exception {
users = Arrays.asList( // 배열을 리스트로 만들어주는 편리한 메소드, 배열을 가변인자로 넣어주면 더욱 편리하다.
new User("bumjin", "박범진", "p1", Level.BASIC, MIN_LOGCOUNT_FOR_SIVER-1, 0, "taxol1203@naver.com"),
new User("joytouch", "강명성", "p2", Level.BASIC, MIN_LOGCOUNT_FOR_SIVER, 0, "taxol1203@gmail.com"),
new User("erwins", "신승한", "p3", Level.SILVER, 60, MIN_RECOMMEND_FOR_GOLD-1, "taxol1203@daum.com"),
new User("madnitel", "이상호", "p4", Level.SILVER, 60, MIN_RECOMMEND_FOR_GOLD, "taxol1203@kakao.com"),
new User("green", "오민규", "p5", Level.GOLD, 100, Integer.MAX_VALUE, "taxol1203@hanmail.net")
);
}
// 5-17 userService 빈의 주입을 확인하는 테스트
@Test
public void bean() {
assertNotNull(this.userService);
}
// 5-30 개선한 레벨 업그레이드 테스트
@Test
@DirtiesContext
public void upgradeLevels() {
userDao.deleteAll();
for(User user : users) userDao.add(user);
// 메일 발송 결과를 테스트할 수 있도록 목 오브젝트를 만들어 userService의 의존 오브젝트로 주입한다.
MockMailSender mockMailSender = new MockMailSender();
//userServiceImpl.setMailSender(mockMailSender);
userService.upgradeLevels();
// 각 사용자별로 업그레이드 후의 예상 레벨을 검증한다.
checkLevelUpgraded(users.get(0), false);
checkLevelUpgraded(users.get(1), true);
checkLevelUpgraded(users.get(2), false);
checkLevelUpgraded(users.get(3), true);
checkLevelUpgraded(users.get(4), false);
// 목 오브젝트에 저장된 메일 수신자 목록을 가져와 업그레이드 대상과 일치하는지 확인 한다.
List<String> request = mockMailSender.getRequests();
assertThat(request.size(), is(2));
assertThat(request.get(0), is(users.get(1).getEmail()));
assertThat(request.get(1), is(users.get(3).getEmail()));
}
// DB에서 사용자 정보를 가져와 레벨을 확인하는 코드가 중복되므로 헬퍼 메소드로 분리했다.
private void checkLevelUpgraded(User user, boolean upgraded) {
User userUpdate = userDao.get(user.getId());
if(upgraded) {
assertEquals(userUpdate.getLevel(), user.getLevel().nextLevel()); // 업그레이드가 일어났는지 확인
}
else {
assertEquals(userUpdate.getLevel(), user.getLevel()); // 업그레이드가 일어나지 않았는지 확인
}
}
// 5-21 add() 메소드의 테스트
@Test
public void add() {
userDao.deleteAll();
User userWithLevel = users.get(4); // GOLD 레벨
User userWithoutLevel = users.get(0);
userWithoutLevel.setLevel(null); // 레벨이 비어 있는 사용자. 로직에 따라 등록 중에 BASIC 레벨도 설정돼야 한다.
userService.add(userWithLevel);
userService.add(userWithoutLevel);
// DB에 저장된 결과를 가져와 확인한다.
User userWithLevelRead = userDao.get(userWithLevel.getId());
User userWithoutLevelRead = userDao.get(userWithoutLevel.getId());
assertEquals(userWithLevelRead.getLevel(), userWithLevel.getLevel());
assertEquals(userWithoutLevelRead.getLevel(), Level.BASIC);
}
@Test
public void upgradeAllOrNothing() throws Exception {
userDao.deleteAll();
for (User user : users) {
userDao.add(user);
}
try {
this.testUserService.upgradeLevels();
fail("TestUserService Exception expected");
} catch (TestUserServiceException e) {
System.out.println("test failed");
}
checkLevelUpgraded(users.get(0), false);
checkLevelUpgraded(users.get(1), false);
checkLevelUpgraded(users.get(2), false);
checkLevelUpgraded(users.get(3), false);
checkLevelUpgraded(users.get(4), false);
}
static class TestUserServiceImpl extends UserServiceImpl {
private String id = "madnite1"; // 테스트 픽스처의 값을 이제 가져올 수 없기에 고정
protected void upgradeLevel(User user) {
if (user.getId().equals(this.id)) {
throw new TestUserServiceException();
}
super.upgradeLevel(user);
}
}
static class TestUserServiceException extends RuntimeException {
}
}NameMatchClassMethodPointcut
package com.taxol.proxy;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.util.PatternMatchUtils;
public class NameMatchClassMethodPointcut extends NameMatchMethodPointcut {
// 모든 클래스를 다 허용하던 디폴트 클래스 필터를 프로퍼티로 받은 클래스 이름을 이용해서 필터를 만들어 덮어씌운다.
public void setMappedClassName(String mappedClassName){
this.setClassFilter(new SimpleClassFilter(mappedClassName));
}
static class SimpleClassFilter implements ClassFilter{
String mappedName;
private SimpleClassFilter(String mappedName) {
this.mappedName = mappedName;
}
@Override
public boolean matches(Class<?> clazz) {
// 와일드카드(*)가 들어간 문자열 비교를 지원하는 스프링의 유틸리티 메소드다.
// *name, name*, *name* 세 가지 방식을 모두 지원한다.
return PatternMatchUtils.simpleMatch(mappedName, clazz.getSimpleName());
}
}
}Reactions are currently unavailable