在完成了数据访问层的单元之后,接下来看如何编写服务层(Service)的单元测试。服务层应该是整个系统中得重中之重,严密的业务逻辑设计保证了系统稳定运行,所以这一层的单元测试也应该占很大比重。虽然一般情况下单元测试应该尽量通过mock剥离依赖,但是由于在当前的项目中数据访问层使用spring-data框架,并没有包含太多的逻辑,因此我就把服务层和数据访问层放在做了一个伪单元测试。
一、一般逻辑的单元测试。
这里采用的方式和数据访问层几乎是一样的,主要包含三步:
1. 通过@DatabaseSetup指定测试用数据集
2. 执行被测试方法
3. 通过Dao从数据库中查询数据验证执行结果
假设要被测试的代码方法是:
@Service
@Transactional(readOnly = true)
public class ShopServiceImpl extends BaseService implements ShopService{
private Logger logger = LoggerFactory.getLogger(ShopServiceImpl.class);
@Transactional(readOnly = false)
public Floor addFloor(String buildingName, int floorNum, String layout) {
//如果已经存在对应的楼层信息,则抛出已经存在的异常信息
Floor floor = floorDao.findByBuildingNameAndFloorNum(buildingName, floorNum);
if (floor != null) {
throw new OnlineShopException(ExceptionCode.Shop_Floor_Existed);
}
//如果不存在对应的商场信息,则添加新的商场
Building building = buildingDao.findByName(buildingName);
if (building == null) {
building = new Building();
building.setName(buildingName);
buildingDao.save(building);
}
//添加并返回楼层信息
floor = new Floor();
floor.setBuilding(building);
floor.setFloorNum(floorNum);
floor.setMap(layout);
floorDao.save(floor);
return floor;
}
}
其对应的接口是:
public interface ShopService {
public Floor addFloor(String buildingName, int floorNum, String layout);
}
这段逻辑代码的意思十分简单和直白,那么要编写的单元的测试必须要包含所有分支情况:a. 商场和楼层信息都存在的,抛出异常 b. 商场存在,而楼层不存在, 楼层信息都被添加的。 c. 商场和楼层都不存在,全部新增。这里就以第一种情况为例,先准备测试数据:
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<building id="1" name="New House"/>
<floor id="1" building="1" floor_num="2"/>
</dataset>
接着编写测试用例,注意要必须得注解不能忘掉:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@Transactional
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
CustomTransactionDbUnitTestExecutionListener.class,
ForeignKeyDisabling.class})
public class ShopServiceTest {
@Autowired
private ShopService shopService;
@Test
@DatabaseSetup("shop/ShopService-addFloorExistException-dataset.xml")
public void testAddFloorExistException(){
try {
shopService.addFloor("New House", 2, "");
fail();
} catch(Exception e){
assertTrue(e instanceof OnlineShopException);
assertEquals(ExceptionCode.Shop_Floor_Existed.code(), ((OnlineShopException)e).getCode());
}
}
}
这个测试和数据访问层的测试看起来没有什么两样。
二、使用Mock对象隔离第三方接口 软件开发中一般都存在和第三方集成的情况,比如调用新浪的认证、百度的地图等等。那么在编写测试的时候,基于效率的考虑,一般情况不会真的去调用这些远程API(当然应该有其他测试可以及时发现第三方接口的变化),而是假定它们一直会返回预期的结果。这个时候就需要用到mock对象,来模拟这些API产生相应的结果。
在这里,我是用了mockito,使用十分方便。假如现在用户登录时,需要去第三方系统验证,那么现在来看如何对这个场景进行测试。还是先来看被测试的方法:
private boolean validateUser(String inputName, String inputPassword) {
return thirdPartyAPI.authenticate(inputName, inputPassword);
}
其中thirdPartyAPI就是第三方用来认证的API。下面来看测试代码:
public class UserServiceTest {
@Autowired
private UserService userService;
private ThirdPartyAPI mockThirdPartyAPI = mock(ThirdPartyAPI.class);
@Test
public void testLogin(){
//指定mock对象特定操作的返回结果
when(mockThirdPartyAPI.authenticate("jiml", "jiml")).thenReturn(true);
//通过Setter用mock对象替换由Spring初始化的第三方依赖
((UserServiceImpl)userService).setThirdPartyAPI(mockThirdPartyAPI);
boolean loginStatus = userService.login("jiml", "jiml");
assertTrue(loginStatus);
}
}
其实服务层的测试并没有太多的新东西,而最关键的问题是如何把逻辑中各个分支都能测试到,使测试真正起到为软件质量保驾护航的作用。
分享到:
相关推荐
在编写数据访问层的单元测试时,遇到不少问题,有些问题可以很容易Google到解决方法,而有些只能自己研究解决。这里分享几个典型的问题以及解决方法。先交代一下用到的测试框架SpringTest+SpringTestDbUnit+DbUnit。...
翻看之前的文章才发现,最近一次记录持续集成竟然是3年前,并且...说起来可笑,从3年前第一次准备做持续集成式,就开始考虑测试数据访问层的一些问题: 难道我要在测试服务器上装一个MySQL? 数据库结构发生了变化怎
Sonar是一个用于代码质量管理的开放平台,通过插件机制,Sonar可以集成不同的测试工具、代码分析工具以及持续集成工具。与持续集成工具(如Hudson/Jenkins等)不同,Sonar并不是简单地把不同代码检查结果(例如:...
持续集成倡导开发团队频繁地进行系统集成——通常一天一次到数次,每次集成都能被自动编译和测试验证,从而能在最短的时间内发现问题,缩短开发周期,提高软件 持续集成作为一种敏捷软件开发实践,已经被越来越多...
2023中国互联网测试开发...云真机自动化测试平台建设实践之路 游戏实时代码染色系统 6、质量保障 云原生全链路压测体系 大数据测试体系 客诉舆情风险智能应急快反 隐私计算测试体系建设 DevOps平台在实业的生根发芽
——学习参考资料:仅用于个人学习使用! 本代码仅作学习交流,切勿用于商业用途,否则后果自负。若涉及侵权,请联系,会尽快处理! 未进行详尽测试,请自行调试!
目前,持续集成已成为当前许多软件开发团队在整个软件开发生命周期内侧重于保证代码质量的常见做法。随着测试的自动化率逐步提高,每天要需要自动执行的测试用例也就越来越多了,当我们发现,跑一次完整的测试需要几...
《Jenkins权威指南》适合想要了解Jenkins工具以及持续集成、持续交付理念的开发和测试人员阅读,也非常适合基于Jenkins构建持续集成、持续交付平台的技术人员阅读。 目录 第1 章 Jenkins 简介 1 第2 章 迈入...
编写的持续集成软件。 Cerberus 可以定期从调度程序运行以检查应用程序测试是否被破坏。 在测试失败的情况下,Cerberus 将通过各种方式发送通知警报。 Cerberus 完美适用于 Windows 和 *nix 平台。 有关更多 CI 理论...
书中首先从OOP 采用的机制—— ... 试、部署和持续集成第三部分 SPL(标准PHP库) 第9章 SPL简介 第10章 SPL迭代器 第11章 SPL文件和目录处理 第12章 SPL数组重载 第13章 SPL异常第四部分 MVC模式 等 。。
——学习参考资料:仅用于个人学习使用! 本代码仅作学习交流,切勿用于商业用途,否则后果自负。若涉及侵权,请联系,会尽快处理! 未进行详尽测试,请自行调试!
) 的持续集成 DevOps 和测试——fabric、ansible、docker 总结:什么是有效的测试? 概括 几年前,在 Python 世界中进行测试被视为一种奢侈。 如今,它更像是一种必备品。 本报告将介绍 Python 生态系统中一些有用...
这是一个免费的源代码,可以处理任何类型的构建或持续集成。集成Jenkins可以用于一些测试和部署技术。Jenkins是一种允许持续集成的软件。持续、自动地构建/测试软件项目。更好地实现整个CICD流程。开源的java语言...
10 Devops全自动化持续集成和持续交付、部署 11、KubeSphere自动化运维 12、动态扩展,弹性自动伸缩 13.高并发下的服务降级、限流实战 14.实现高并发请求和实现高可用架构解决方案 15.引入大数据技术 16、引入人工...
反射API 第8章 测试、部署和持续集成 第三部分 SPL(标准PHP库) 第9章 SPL简介 第10章 SPL迭代器 第11章 SPL文件和目录处理 第12章 SPL数组重载 第13章 SPL异常 第四部分 MVC模式 第14章 MVC架构 第15章 ...
测试、部署和持续集成 第三部分 SPL(标准PHP库) 第9章 SPL简介 第10章 SPL迭代器 第11章 SPL文件和目录处理 第12章 SPL数组重载 第13章 SPL异常 第四部分 MVC模式 第14章 MVC架构 第15章 Zend框架简介 第16章 Zend...
CI——持续集成(持续集成) CSS - 层叠样式表 DDD - 领域驱动设计 开发人员 - 开发人员 HTML - 超文本标记语言 AI——智能人工(人工智能) GCP - 谷歌云平台 JS - JavaScript LESS - 更精简的样式表 Lib - 图书馆...
代码审查、类/包设计、TDD、持续集成速查表 Urs Enzler花了大约一年半的时间整理了这份速查表,旨在帮助开发者检查代码是否洁净 ...•TDD——测试驱动开发 •ATDD——检验测试驱动开发 •持续集成
适用于 Android 的持续集成 / 继续打造宝贝! – 恩里克·洛佩斯 优雅的?? 单元测试——巴勃罗·瓜迪奥拉 注释处理工具——Txus Ballesteros Android Wear与Tizen – Saul M. 使用 Scala 进行无痛 Android ...