关于BUG指标
- 代码覆盖率(30%)–(60%)(80%)
- 圈复杂度
- 每千行代码bug数(60)–(10-20)
质量相关的指标
- 120(完全不写单元测试)
- 30(有经验的,写点单元测试的)
单元测试
- 最简单的 main 方法
- Junit/TestNG 工具
单元测试的原则
- 单元测试可以无限次重跑
- 一定要有Assert
- 单元测试一定不要依赖外部环境
带事务
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath: application-test.xml"})
// 所有的插入修改都不生效
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class MenuInfoServiceTest(){
@Autowired
private MenuInfoService menuInfoService;
@Test
public void test1() throws Exception {
MenuInfo menuInfo = new MenuInfo();
// menuInfo.setId(11);
menuInfo.setMemo("senvon");
Integer i = menuInfoService.saveMenuInfo(menuInfo);
// System.out.println("===================" + i);
Assert.assertTrue(i > 0);
MenuInfo result = menuInfoService.findMenuInfoById(i);
Assert.assertTrue(result != null);
Assert.assertTrue("senvon".equalesIgnoreCase(result.getMeno()));
}
}
测试分类
- 墨盒/白盒
- 单元测试属于白盒, 其它属于墨盒(开发只负责白盒测试)
- 集成测试
- 功能测试
- 回归测试
- 性能测试
多线程测试(CountDownLatch)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath: application-test.xml"})
// 所有的插入修改都不生效
//@TransactionConfiguration(defaultRollback = true)
//@Transactional
public class MenuInfoServiceTest(){
@Autowired
private MenuInfoService menuInfoService;
@Test
public void test2() throws Exception {
for(int i = 0 ; i < 100 ; i ++){
Thread t = new Thread(new ExecuteThread(14));
t.start();
latch.countDown();
}
// 因为Junit是单线程运行没等到运行结束你进程结束了
Thread.currentThread().sleep(3000);
}
@Before
public void init() throws Exception {
}
@After
public void destory() throws Exception {
menuInfoService.deleteMenuINfoByName("senvon");
}
private CountDownLatch latch = new CountDownLatch(100);
private Long total = 0L;
private Integer totalCount = 0;
private class ExecuteThread implements Runnable {
private Long amount;
public ExecuteThread(Long amount){
this.amount = amount;
}
public void run() {
try{
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
MenuInfo menuInfo = new MenuInfo();
// menuInfo.setId(11);
menuInfo.setMemo("senvon");
Integer i = menuInfoService.saveMenuInfo(menuInfo);
MenuInfo menuInfoResult = service.findMenuInfoById(i);
System.out.println("=============================" + menuInfoResult);
Assert.assertTrue(menuInfoResult != null);
}
}
}
远程调用 RPC 外部请求 (Mock 自己实现接口)
接口测试 复杂参数 (MockHttpServletRequest)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath: application-test.xml"})
// 所有的插入修改都不生效
//@TransactionConfiguration(defaultRollback = true)
//@Transactional
public class MenuInfoServiceTest(){
@Autowired
MenuInfoController controller;
@Test
public void test1() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("name", "senvonaasf");
HttpSession session = request.getSession();
session.setAttribute("name", "senvonInSession");
Map<String, Object> result = controller.test(request);
Assert.assertTrue(result != null);
Assert.assertTrue("123".equalsIgnoreCase(result.get("returnCode") + ""));
}
}
Coverage