单元测试的好处不用多说,就光光是能减少bug,减少调试时间,就值得我们认真去对待。
偷个懒,文章基于springboot配置单元测试
引入jar包
org.springframework.boot
spring-boot-starter-test
test
使用@RunWith、@SpringBootTest和@Test注解
在编写单元测试的类上加上上面两个注解即可。这里的App是springboot项目的启动类。
@RunWith(SpringRunner.class)
@SpringBootTest(classes=App.class)
public class Test{
@Test
public void methodA() {
System.out.println("do something..");
}
}
1、单元测试的方法不能有返回值(比如上面的methodA()方法只能是void);
2、单元测试的方法不能用static修饰、且只能是public权限修饰;
3、maven项目结构中,一般都把单元测试写到../src/test/java路径下;
4、写单元测试不能只关注运行正常的情况,要考虑各种多变的因素(比如参数的多变性,需要更换不同的参数测试);
5、写单元测试不能只关注最小的运行单元,在复杂的业务中,还应该将单个业务联系起来进行集成测试(将多个小单元集成到一个方法中去);
.......(想到了再补充吧)
@RunWith(SpringRunner.class)
@SpringBootTest(classes=App.class)
public class Test {
@Test
public void methodA() {
System.out.println("do something..");
}
}
直接使用@Autowired注入dao层接口即可。
@RunWith(SpringRunner.class)
@SpringBootTest(classes=App.class)
public class UserDaoTest {
@Autowired
private UserDao userDao;
@Test
public void getUserByIdTest() {
String userId = "x123";
UserPO userPO = userDao.getUserById(userId);
System.out.println(userPO.toString());
}
}
添加事务
利用上面的方式进行,如果对数据库进行了写操作,数据会写到数据库中。
如果想在单元测试后,不把数据写到数据库中,需要回滚。可以通过@Rollback配合声明式事务@Transactional注解来实现。
使用事务之前,如果是普通的spring项目需要在配置文件中开启对声明式事务的支持。
springboot项目中需要注解@EnableTransactionManagement,标记在启动类上,开启对声明式事务的支持。
@Test
@Transactional //标记在类上,所有方法都被声明式事务控制
@Rollback(true) //只有一个属性,默认为true,事务会回滚,不将数据写入数据库;false时事务不会回滚,数据会写到数据库中
public void methodATest() throws Throwable {
//do something...
}
直接使用@Autowired注入service接口即可。
@RunWith(SpringRunner.class)
@SpringBootTest(classes=App.class)
public class IUserServiceTest {
@Autowired
private IUserService iUserService;
@Test
public void getUserByIdTest() {
String userId = "x123";
UserDTO userDTO = iUserService.getUserById(userId);
System.out.println(userDTO.toString());
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes=App.class)
public class UserControllerTest {
@Autowired
private UserController userController;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
}
@Test
public void listUsersTest() {
//构建请求参数
MultiValueMap params = new LinkedMultiValueMap<>();
params.set("paramA", "x123");
params.set("paramB", "a123");
params.set("paramC", "c123");
//构建请求 uri--/user/listUsers 请求方式get 这里还能使用json、设置session、cookie等.
ResultActions resultActions = this.mockMvc.perform(MockMvcRequestBuilders.get("/user/listUsers").params(params));
MvcResult mvcResult = resultActions.andReturn();
String result = mvcResult.getResponse().getContentAsString();
System.out.println("客户端获得的返回数据==="+result);
// 也可以从response里面取状态码,header,cookies...
System.out.println(mvcResult.getResponse().getStatus());
}
}
传递json的接口测试(备注:还可同时支持json+普通的表单参数)
junit本身是不支持多线程的,可以new Thread()测试一下,会运行不了。这是因为Junit的底层实现上,是用System.exit退出用例执行的,JVM都终止了,在测试线程启动的其他线程自然也无法执行。
所以,可以利用三方工具:GroboUtils。
GroboUtils官网:http://groboutils.sourceforge.net/
GroboUtils下载页面:http://groboutils.sourceforge.net/downloads.html
maven引入方式:
net.sourceforge.groboutils
groboutils-core
5
简单的示例:
@Test
public void methodATest() throws Throwable {
// 构造一个Runner
TestRunnable runner = new TestRunnable() {
@Override
public void runTest() throws Throwable {
// 测试内容 do something.....
}
};
// 并发线程数量
int runnerCount = 100;
TestRunnable[] trs = new TestRunnable[runnerCount];
for (int i = 0; i < runnerCount; i++) {
trs[i] = runner;
}
// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
// 并发执行测试内容
mttr.runTestRunnables();
}