本篇主要介绍PowerMock + Spring + Mybatis + H2单元测试,接上篇:https://www.cnblogs.com/javaXRG/p/17538157.html
1 PowerMock
1.1 Mockito的不足
- 不支持局部变量
- 不支持mock静态方法
- 不支持mock final修饰的类或方法
- 不支持mock私有方法
1.2 PowerMock局部变量
1 package org.example.service; 2 3 import org.example.Domain.User; 4 import org.example.dao.UserDao; 5 6 public class UserService2 { 7 8 public User findUser(String userName, String password) { 9 // 需要mock局部变量 userDao 10 UserDao userDao = new UserDao(); 11 return userDao.findUser(userName, password); 12 } 13 }
1 package org.example.powermock; 2 3 import lombok.SneakyThrows; 4 import org.example.Domain.User; 5 import org.example.dao.UserDao; 6 import org.example.service.UserService2; 7 import org.junit.Test; 8 import org.junit.runner.RunWith; 9 import org.powermock.api.mockito.PowerMockito; 10 import org.powermock.core.classloader.annotations.PrepareForTest; 11 import org.powermock.modules.junit4.PowerMockRunner; 12 13 import static org.junit.Assert.assertEquals; 14 import static org.powermock.api.mockito.PowerMockito.when; 15 import static org.powermock.api.mockito.PowerMockito.whenNew; 16 17 @RunWith(PowerMockRunner.class) 18 @PrepareForTest({UserService2.class, UserDao.class}) 19 public class LocalVariableTest { 20 21 @Test 22 @SneakyThrows 23 public void findUserTest() { 24 UserService2 userService2 = new UserService2(); 25 UserDao userDao = PowerMockito.mock(UserDao.class); 26 whenNew(UserDao.class).withNoArguments().thenReturn(userDao); 27 // 此处用PowerMockito或Mockito的when()都可 28 when(userDao.findUser("zhangsan", "123456")).thenReturn(new User(1L, "zhangsan", "123456")); 29 User user = userService2.findUser("zhangsan", "123456"); 30 assertEquals(1, user.getId().longValue()); 31 } 32 }
1.3 PowerMock静态方法
package org.example.service; public class StaticMethod { public static String get() { return null; } }
package org.example.powermock; import org.example.service.FinalClass; import org.example.service.StaticMethod; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.junit.Assert.assertNotNull; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @RunWith(PowerMockRunner.class) @PrepareForTest({StaticMethod.class}) public class StaticMethodTest { @Test public void getUser() { mockStatic(StaticMethod.class); when(StaticMethod.get()).thenReturn(""); String value = StaticMethod.get(); assertNotNull(value); } }
高版本的Mockito也支持static方法的mock
1.4 PowerMock final类
1 package org.example.service; 2 3 import org.example.Domain.User; 4 import org.example.dao.UserDao; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.stereotype.Service; 7 8 @Service 9 public final class FinalClass { 10 11 @Autowired 12 private UserDao userDao; 13 14 public User findUser(String userName, String password) { 15 return userDao.findUser(userName, password); 16 } 18 }
测试中,发现Mockito也支持final类的mock
1 package org.example.powermock; 2 3 import org.example.Domain.User; 4 import org.example.dao.UserDao; 5 import org.example.service.FinalClass; 6 import org.junit.Test; 7 import org.junit.runner.RunWith; 8 import org.mockito.InjectMocks; 9 import org.mockito.Mock; 10 import org.mockito.junit.MockitoJUnitRunner; 11 12 import static org.junit.Assert.assertEquals; 13 import static org.junit.Assert.assertNotNull; 14 import static org.powermock.api.mockito.PowerMockito.when; 15 16 @RunWith(MockitoJUnitRunner.class) 17 public class MockitoTest { 18 19 @InjectMocks 20 private FinalClass finalClass; 21 22 @Mock 23 private UserDao userDao; 24 25 @Test 26 public void findUserTest() { 27 when(userDao.findUser("", "")).thenReturn(new User(1L, "zhangsan1", "123456")); 28 User user = finalClass.findUser("", ""); 29 assertNotNull(user); 30 assertEquals("zhangsan1", user.getUserName()); 31 } 32 }
PowerMock mock filanl类:
1 package org.example.powermock; 2 3 import org.example.Domain.User; 4 import org.example.dao.UserDao; 5 import org.example.service.FinalClass; 6 import org.example.service.UserService2; 7 import org.junit.Test; 8 import org.junit.runner.RunWith; 9 import org.mockito.InjectMocks; 10 import org.mockito.Mock; 11 import org.powermock.core.classloader.annotations.PrepareForTest; 12 import org.powermock.modules.junit4.PowerMockRunner; 13 14 import static org.junit.Assert.assertNotNull; 15 import static org.powermock.api.mockito.PowerMockito.when; 16 17 @RunWith(PowerMockRunner.class) 18 @PrepareForTest({FinalClass.class}) 19 public class FinalClassTest { 20 21 @InjectMocks 22 private FinalClass finalClass; 23 24 @Mock 25 private UserDao userDao; 26 27 @Test 28 public void findUserTest() { 29 when(userDao.findUser("", "")).thenReturn(new User(1L, "zhangsan", "123456")); 30 User user = finalClass.findUser("", ""); 31 assertNotNull(user); 32 } 33 }
1.5 PowerMock私有方法
package org.example.service; import org.example.Domain.User; public class PrivateMethod { public User findUser(String userName) { // do something return getUser(userName); } private User getUser(String userName) { return null; } }
package org.example.powermock; import lombok.SneakyThrows; import org.example.Domain.User; import org.example.service.PrivateMethod; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.junit.Assert.assertNotNull; import static org.powermock.api.mockito.PowerMockito.spy; import static org.powermock.api.mockito.PowerMockito.when; @RunWith(PowerMockRunner.class) @PrepareForTest({PrivateMethod.class}) public class PrivateMethodTest { @SneakyThrows @Test public void findUserTest() { PrivateMethod privateMethod = spy(new PrivateMethod()); when(privateMethod, "getUser", "").thenReturn(new User(1L, "zhangsan", "123456")); User user = privateMethod.findUser(""); assertNotNull(user); } }
1.6 说明
虽然PowerMock功能强大,但不推荐使用, 因为其一些功能可能打破了java的设计理念,编写单元测试时,尽量编写可测试的代码,如果代码不可测,很可能是其结构设计有问题
2 Spring-test
2.1 多层依赖嵌套
package org.example.controller; import org.example.Domain.User; import org.example.dao.UserDao; import org.example.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.context.annotation.Import; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; /** * @RunWith(SpringJUnit4ClassRunner.class) 启动spring单元测试运行器 * @Import({UserController.class}) 使@Autowired UserController生效 */ @RunWith(SpringJUnit4ClassRunner.class) @Import({UserController.class}) public class UserControllerTest1 { @Autowired private UserController userController; /** * spy对象并注入spring容器 */ @SpyBean private UserService userService; /** * mock对象并注入spring容器 */ @MockBean private UserDao userDao; @Test public void findUserTest() { when(userDao.findUser("zhangsan", "123456")).thenReturn(new User(100L, "zhangsan", "123456")); User user = userController.findUser("zhangsan", "123456"); assertEquals(100L, user.getId().longValue()); } }
3 Mybatis + H2
init.sql:
1 create table if not exists user_info ( 2 `id` int(11) not null, 3 `user_name` varchar(256) not null, 4 `password` varchar(256) not null 5 );
dataSource.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:p="http://www.springframework.org/schema/p" 4 xmlns="http://www.springframework.org/schema/beans" 5 xmlns:jdbc="http://www.springframework.org/schema/jdbc" 6 xmlns:context="http://www.springframework.org/schema/context" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans.xsd 9 http://www.springframework.org/schema/tx 10 http://www.springframework.org/schema/tx/spring-tx.xsd 11 http://www.springframework.org/schema/jdbc 12 http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 13 http://www.springframework.org/schema/context 14 http://www.springframework.org/schema/context/spring-context.xsd"> 15 16 <jdbc:embedded-database id="h2TestDataSource" type="H2" database-name="testDataSource;DATABASE_TO_UPPER=false;MODE=MYSQL;"> 17 <!-- 这里init.sql是需要初始化的文件 --> 18 <jdbc:script location="classpath:init.sql"/> 19 </jdbc:embedded-database> 20 21 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 22 <property name="dataSource" ref="h2TestDataSource"/> 23 <!--<property name="mapperLocations"> 24 <list> 25 <!– 这里的value换成真实的mybatis的mapper文件地址 –> 26 <value>classpath:mybatis/*Mapper.xml</value> 27 </list> 28 </property>--> 29 </bean> 30 31 <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> 32 <constructor-arg ref="sqlSessionFactory"/> 33 </bean> 34 35 <!-- 配置扫描Mapper接口的包路径 --> 36 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 37 <!-- xxxMapper.java对应的包名 --> 38 <property name="basePackage" value="org.example.mapper"/> 39 <property name="sqlSessionFactory" ref="sqlSessionFactory"/> 40 </bean> 41 42 <!-- 数据库事务管理配置 --> 43 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 44 <property name="dataSource" ref="h2TestDataSource"/> 45 </bean> 46 47 <!-- spring扫描路径 --> 48 <context:component-scan base-package="org.example"/> 49 </beans>
UserMapper:
1 package org.example.mapper; 2 3 import org.apache.ibatis.annotations.Select; 4 import org.example.Domain.User; 5 import org.springframework.stereotype.Repository; 6 7 @Repository 8 public interface UserMapper { 9 10 @Select("select * from user_info where id = #{id}") 11 User findUserById(Long id); 12 }
Test:
1 package org.example; 2 3 import org.example.Domain.User; 4 import org.example.mapper.UserMapper; 5 import org.junit.Test; 6 import org.junit.runner.RunWith; 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.test.context.ContextConfiguration; 9 import org.springframework.test.context.jdbc.Sql; 10 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 12 import static org.junit.jupiter.api.Assertions.assertEquals; 13 import static org.junit.jupiter.api.Assertions.assertNotNull; 14 15 @RunWith(SpringJUnit4ClassRunner.class) 16 @ContextConfiguration(locations = "classpath:dataSource.xml") 17 public class UserServiceTest { 18 19 @Autowired 20 private UserMapper userMapper; 21 22 @Test 23 // 使用该语句先插入一条数据 24 @Sql(statements = { 25 "insert into user_info (id, user_name, password) values(1,'zs','123456');" 26 }) 27 public void findUserById() { 28 User user = userMapper.findUserById(1L); 29 assertNotNull(user); 30 assertEquals("zs", user.getUserName()); 31 } 32 }
标签:单元测试,junit,example,User,import,org,class From: https://www.cnblogs.com/javaXRG/p/17539204.html