单元测试规范
文章目录背景UT规范1.DAO层2.Service层2.1 方式一2.2 方式二(推荐)3.接入Jacoco插件4.接入Jenkins背景UT的作用:减少花在联调的时间提高代码质量减少bug,快速定位bug放心地修改、重构显得专业UT规范1.DAO层难题:在测试单测环境数据库的前提下,写DAO层的单元测试时,往往测试用例所依赖的数据库数据被修改或删除了,或者在一个新的环境下...
·
背景
UT的作用:
- 减少花在联调的时间
- 提高代码质量
- 减少bug,快速定位bug
- 放心地修改、重构
- 显得专业
UT规范
1.DAO层
难题:在测试单测环境数据库的前提下,写DAO层的单元测试时,往往测试用例所依赖的数据库数据被修改或删除了,或者在一个新的环境下所依赖的数据库不存在,导致单元测试无法通过,进而构建失败。
思想:使用H2内存数据库来模拟数据库环境是一个很好的解决方案
示例:
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:db/schema.sql" />
<jdbc:script location="classpath:db/data.sql" />
</jdbc:embedded-database>
其中schema.sql存放的建表sql,data.sql存放的是数据准备sql,依赖具体业务表和数据
@Test
public void insertTest() {
ActTemplateItem actTemplateItem = getActTemplateItem();
long row = actTemplateItemMapperExt.insertSelective(actTemplateItem);
Assert.assertEquals(1, row);
}
2.Service层
难点有几个:
- UT全走通全链路,但不依赖第三方库(其他服务和第三方平台)
- 养成测试驱动开发的好习惯
- 整个打包过程的性能
2.1 方式一
思想:外部依赖全部mock,只测试方式本身的业务逻辑
示例:
@RunWith(MockitoJUnitRunner.class)
public class ActTemplateItemServiceTest {
@InjectMocks
private ActTemplateItemServiceImpl actTemplateItemService;
@Mock
private ActTemplateItemMapperExt actTemplateItemMapperExt;
@Test
public void listByTemplateIdTest() {
ActTemplateItem actTemplateItem = ActTemplateItemBuilder.buildActTemplateItem();
when(actTemplateItemMapperExt.selectByTemplateId(any())).thenReturn(Lists.newArrayList(actTemplateItem));
List<ActTemplateItemDTO> result = actTemplateItemService.listByTemplateId(1L);
Assert.assertEquals("34", result.get(0).getBrandPageId());
}
}
优点:(1)轻量级 (2)最小单元测试
缺点:(1)无法激起开发人员写UT心情 (2)无法测试整个方式链路的情况,易忽略特殊情况
2.2 方式二(推荐)
思想:增加unittest环境(目前配置环境和test共用一套,日后可单独配置并去除无用配置),走通单元测试方式全链路,依赖的第三方库采用mock方式,自己的内部Service及Dao层依赖走真实数据库(H2内存数据库)
示例:
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:db/schema.sql" />
<jdbc:script location="classpath:db/data.sql" />
</jdbc:embedded-database>
public class ActTemplateItemServiceTest extends AbstractBaseTest {
@Autowired
private ActTemplateItemServiceImpl actTemplateItemService;
@Mock
private ItemAdapter spyItemAdapter;
@Autowired
private RedisService redisService;
@Before
public void before() {
MockitoAnnotations.initMocks(this);
MockitoAnnotations.initMocks(spyItemAdapter);
ReflectionTestUtils.setField(actTemplateItemService, "itemAdapter", spyItemAdapter);
Mockito.when(spyItemAdapter.listItemFrontPrimaryCategory()).thenReturn(getCategoryList());
}
@Test
public void listByTemplateIdTest() {
List<ActTemplateItemDTO> result = actTemplateItemService.listByTemplateId(1L);
Assert.assertEquals("https://mall.hipac.cn/ytms/page/kqfsms_h5.html", result.get(0).getBrandPageId());
}
@Test
public void listItemPrimaryCategoryTest() {
RedisKeyUtils.RedisKey key = RedisKeyUtils.getItemCategoryListKey();
redisService.del(key.getKey());
List<ItemFrontPrimaryCategoryDTO> result = actTemplateItemService.listItemPrimaryCategory();
System.out.println(result);
Assert.assertEquals(2, result.size());
}
private List<ItemFrontPrimaryCategoryDTO> getCategoryList() {
List<ItemFrontPrimaryCategoryDTO> categoryList = Lists.newArrayList();
ItemFrontPrimaryCategoryDTO categoryDTO1 = new ItemFrontPrimaryCategoryDTO();
categoryDTO1.setPrimaryCategoryId(1L);
categoryDTO1.setPrimaryCategoryName("尿不湿");
categoryList.add(categoryDTO1);
ItemFrontPrimaryCategoryDTO categoryDTO2 = new ItemFrontPrimaryCategoryDTO();
categoryDTO2.setPrimaryCategoryId(2L);
categoryDTO2.setPrimaryCategoryName("婴儿车");
categoryList.add(categoryDTO2);
return categoryList;
}
}
优点:(1)便于发现测试方法的问题(2)刺激开发人员写单元测试的激情
缺点:(1)需要加载整个启动环境(2)当单元测试较多的时候,整个打包过程时间会变长(耗费性能点在于sql执行,日后可mock Dao层数据)
3.接入Jacoco插件
<!-- jacoco plugin -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<!--
在maven的initialize阶段,将Jacoco的runtime agent作为VM的一个参数
传给被测程序,用于监控JVM中的调用。
-->
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>
${project.build.directory}/coverage-reports/jacoco.exec
</destFile>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<!--
在程序的verify阶段,执行report测试的程序。
文件的输入为perpare-agent阶段中设置或者默认的jacoco.exec.
参数 includes和excludes可用来选定report中过滤的类。
-->
<execution>
<id>default-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
4.接入Jenkins
不再详情介绍。
更多推荐
已为社区贡献2条内容
所有评论(0)