目录1.指定测试标准2.设计测试用例3.测试集示例4.跑测试集1.指定测试标准单元测试会用到mock和junit的内容作者前文有详解可移步Spring Boot单元测试-CSDN博客mockito的详细使用-CSDN博客1.1.测哪一层以当前后端标准的MVC分层来说后端代码分为controller、service、dao三层。首先我们要先确定这三层里面去测试哪一层单元测试的核心目的是什么覆盖业务代码按标准的来说的话controller层是系统对外暴露的API这一层级只负责做一些请求和参数的处理service层用来编写具体的业务逻辑dao层负责与数据库进行交互。所以我们应该测service层。1.2.如何判断测试是否通过测试的输出结果和我们期望的输出结果是一致的测试就通过了。怎么判断喃用Assert断言Assert不要到处去用在测试用例的最后用它来判断一下输出结果是不是期望值即可。1.3.mock掉哪些内容mock我们主要拿来干两件事儿mock掉对数据库的操作避免引起数据的改动也就是说要mock掉dao层的方法mock掉没办法达到的地方比如有些地方不影响代码逻辑但是在测试的时候不好造出来这些不可达的地方可以mock掉。mock我们要mock两种情况mock返回值mock行为mock返回值比如Train train new Train(); String id UUID.randomUUID() ; train.setKeyId(id); when(trainDao.getDetail(any(Train.class))).thenReturn(train);mock行为有些时候是主动的我们想去定义实体的具体行为有时候是被动的比如要mock的dao方法没有返回值该我们就只能通过去mock行为来使得它不去操作数据库反正核心就是不让它去操作数据库。比如以下方法void trainDetailDao.updateList(XXX)用doAnswer去mock它的响应Test public void modifyTrainDetails(){ ? TrainDetailList trainDetails new TrainDetailList(); ? TrainDetail trainDetail new TrainDetail(); ? trainDetail.setKeyId(UUID.randomUUID()); ? trainDetails.add(trainDetail); ? doAnswer(invocation - { ? ? ? ListTrainDetail trainDetailList (ListTrainDetail) invocation.getArguments()[0]; ? ? ? Assert.assertEquals(trainDetails.getItems(), trainDetailList); ? ? ? return trainDetails; ? }).when(trainDetailDao).updateList(any()); ? trainDetailBaseSvr.modifyTrainDetails(,trainDetails); }2.设计测试用例一个接口只需要一个测试用例吗有时候是不够的。衡量对一个接口的单元测试是不是到位了核心指标是看它的分支覆盖率。代码种的一个方法里面有些时候会存在一些选择分支带判断性质的语句我们设计测试用例的时候要考虑覆盖掉所有分支。最好的办法就是画个流程图设计测试用例的时候要覆盖掉所有流程分支以下以用户买猪肉为一个例子灰色的节点就是要mock掉的细化成流程图流程图的所有出口就是要覆盖的分支有几个出口就应该有几个用例有几个测试方法3.测试集示例以下是作者在工作中编写的一个测试集用例演示了一个简单的对增删改查方法的覆盖。里面演示了如何覆盖有返回值的方法和没有返回值的方法。这里有几个技巧分享一下首先是要mock掉dao层的话我们就要把service里面依赖的dao换成mock出来的dao这里需要用反射的方式强行访问到service里面的dao然后把它替换掉。其次mock掉dao层之后直接new service就行完全不需要用到自动注入也就是不需要用到IOC也就不需要用到RunWith(XXX.class) SpringBootTest(classes XXX.class)之类的注解来启动SpringBoot了。这样跑测试用例的时候省去了启动时间会快很多。public class ExaminationBaseSvrTest extends PropertyControllerBase { IExaminationBaseSvr examinationBaseSvr; ExaminationTargetService examinationTargetService; private ExaminationDao examinationDao; private IDataDicItemBaseMgeSvr dataDicItemBaseMgeSvr; private DataDictionaryItemDao dataDictionaryItemDao; Before public void setUp() throws Exception{ examinationBaseSvr new ExaminationBaseSvr(); Field field ExaminationBaseSvr.class.getDeclaredField(examinationDao); Field dataDicItemBaseMgeSvrField ExaminationBaseSvr.class.getDeclaredField(dataDicItemBaseMgeSvr); Field dataDictionaryItemDaoField DataDicItemBaseMgeSvr.class.getDeclaredField(dataDictionaryItemDao); field.setAccessible(true); dataDicItemBaseMgeSvrField.setAccessible(true); dataDictionaryItemDaoField.setAccessible(true); examinationDao mock(ExaminationDao.class); dataDictionaryItemDaomock(DataDictionaryItemDao.class); dataDicItemBaseMgeSvrmock(DataDicItemBaseMgeSvr.class); field.set(examinationBaseSvr, examinationDao); dataDicItemBaseMgeSvrField.set(examinationBaseSvr,dataDicItemBaseMgeSvr); dataDictionaryItemDaoField.set(dataDicItemBaseMgeSvr,dataDictionaryItemDao); } Test public void addExamination(){ when(examinationDao.insert(any())).thenReturn(1); Examination examination new Examination(); examination.setKeyId(UUID.randomUUID()); Assert.assertEquals(examinationBaseSvr.addExamination(,examination),examination); } Test public void addExcaminations(){ ExaminationList examinations new ExaminationList(); Examination examination new Examination(); examination.setKeyId(UUID.randomUUID()); examinations.add(examination); doAnswer(invocation - { ListExamination examinationList (ListExamination)invocation.getArguments()[0]; Assert.assertEquals(examinationList,examinations.getItems()); return 1; }).when(examinationDao).insertList(any()); examinationBaseSvr.addExaminations(,examinations); } Test public void modifyExamination(){ when(examinationDao.update(any())).thenReturn(1); Examination examination new Examination(); examination.setKeyId(UUID.randomUUID()); Assert.assertEquals(examinationBaseSvr.modifyExamination(,examination),examination); } Test public void modifyExaminations(){ ExaminationList examinations new ExaminationList(); Examination examination new Examination(); examination.setKeyId(UUID.randomUUID()); examinations.add(examination); doAnswer(invocation - { ListExamination examinationList (ListExamination)invocation.getArguments()[0]; Assert.assertEquals(examinationList,examinations.getItems()); return 1; }).when(examinationDao).updateList(examinations.getItems()); examinationBaseSvr.modifyExaminations(,examinations); } Test public void deleteExamination(){ Examination examination new Examination(); examination.setKeyId(UUID.randomUUID()); when(examinationDao.update(any())).thenReturn(1); when(examinationDao.getDetail(any())).thenReturn(examination); Assert.assertEquals(examinationBaseSvr.deleteExamination(,examination.getKeyId(),false),1); } Test public void deleteExaminations(){ ExaminationList examinations new ExaminationList(); Examination examination new Examination(); examination.setKeyId(UUID.randomUUID()); examinations.add(examination); doAnswer(invocation - { ListExamination examinationList (ListExamination)invocation.getArguments()[0]; Assert.assertEquals(examinationList,examinations.getItems()); return 1; }).when(examinationDao).updateList(any()); examinationBaseSvr.deleteExamination(,examinations,false); } }4.跑测试集测试类写完之后类名旁边有一个run的图标点击即可跑整个测试集。其中有普通的run以及带覆盖率报告的run选择带覆盖率的run之后会显示覆盖率相看类里面具体是哪些代码段被覆盖了可以在跑完测试集后进入具体的被测试类代码行旁边会有颜色条绿色表示被cover的内容