这两天在做spring service层的单元测试时,遇到了一些问题。service层会自动注入(autowired)dao层的interface,如何正常测试service层的逻辑,而不真正的触动dao层的代码,即不往数据库做实际操作,变成了一个需要解决的问题。首先,看一下我们service层的代码:
public interface RegisterUserService {
boolean insert(String passid,String msisdn,String email) throws SQLException;
}
@Service("registerUserService")
public class RegisterUserServiceImpl implements RegisterUserService {
private Logger loggor = Logger.getLogger(getClass());
@Autowired
private UserMapper userMapper;
@Autowired
private PassidUserMapper passidUserMapper;
@Autowired
@Qualifier("redisService")
private CacheService redisService;
@Override
@Transactional
public boolean insert(String passid, String msisdn, String email)
throws SQLException {
if (StringUtils.isEmpty(passid))
return false;
User user = new User();
if (!StringUtils.isEmpty(msisdn))
user.setPhoneNo(msisdn);
if (!StringUtils.isEmpty(email))
user.setEmail(email);
PassidUser passidUser = new PassidUser();
String serverCode = ServerCodeConfig.serverCodeMap
.get(PayUtil.ipAddress);
if (StringUtils.isEmpty(serverCode)) {
serverCode = "999";
}
String userid = serverCode + UIDUtil.next();
passidUser.setUserid(userid);
passidUser.setPassid(passid);
user.setPassid(passid);
user.setUserid(userid);
Date date = new Date();
user.setCreateTime(date);
user.setUpdateTime(date);
user.setDeleteFlag(0);
/*if(loggor.isInfoEnabled()){
loggor.info("passid:" + passid + " userid:" + userid + " msisdn:"
+ msisdn + " email:" + email);
}*/
int result = passidUserMapper.insert(passidUser);
if (passidUserMapper.insert(passidUser) > 0
&& userMapper.insertSelective(user) > 0)
redisService.set("passid:" + passid + ":userid", userid);
else
throw new SQLException("数据插入失败,数据回滚");
return true;
}
}
从代码中可以看到,service层的RegisterUserServiceImpl实现了interface RegisterUserService,在这个service中注入了userMapper,PassidUserMapper和RedisService,我们需要mock掉这三个autowired的真实行为,做spring相关的测试,我们选用的mockito进行,实现较为方便,在做spring mockito测试时,需要引入以下dependency :
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
使用@InjectMock置入需要测试的RegisterUserServiceImpl,如下:
@InjectMocks
private RegisterUserService registerUserService = new RegisterUserServiceImpl();
对于需要mock掉的dao层的interface使用@Mock注入:
@Mock
private UserMapper userMapper;
@Mock
private PassidUserMapper passidUserMapper;
@Mock
private CacheService redisService;
注入后,需要对RsgisterUserService和UserMapper,PassidUserMapper,RedisService绑定:
MockitoAnnotations.initMocks(this);
同时,我们期望UserMapper和PassidMapper的功能得到想要的结果:
when(passidUserMapper.insert(any(PassidUser.class))).thenReturn(1);
when(userMapper.insertSelective(any(User.class))).thenReturn(1);
完整的单元测试代码如下:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/resources/conf/springConfig.xml")
public class RegisterUserServiceImplTest {
@InjectMocks
private RegisterUserService registerUserService = new RegisterUserServiceImpl();
@Mock
private UserMapper userMapper;
@Mock
private PassidUserMapper passidUserMapper;
@Mock
private CacheService redisService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(passidUserMapper.insert(any(PassidUser.class))).thenReturn(1);
when(userMapper.insertSelective(any(User.class))).thenReturn(1);
}
@Test
public void testInsert() throws Exception {
String passid = "12344";
String msisdn = "18867131210";
String email = "test@test.cn";
Assert.assertTrue(registerUserService.insert(passid, msisdn, email));
}
}