- 浏览: 536638 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
飞天奔月:
public List<String> gener ...
实践中的重构30_不做油漆匠 -
在世界的中心呼喚愛:
在世界的中心呼喚愛 写道public class A {
...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
在世界的中心呼喚愛 写道在世界的中心呼喚愛 写道在classB ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
在世界的中心呼喚愛 写道在classB的finalize上打断 ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
iteye比较少上,如果可以的话,可以发e-mail交流:ch ...
深入理解ReferenceQueue GC finalize Reference
UT是个好东西,在对代码进行持续重构的过程中,UT可以保证代码的正确性。同时,和产品代码一样,UT也是需要不断重构的。
有一个接口,原始定义和对应的UT如下:
当需求变更时,UT理应做出对应的修改。
新的需求比较简单。
新加入一个参数userId,通过该userId如果可以找到一个UserInfo的话,则返回结果的日期截至点为该UserInfo的最后修改日期。由其他系统保证该修改日期在当前时间之前的某一天。
新的UT如下:
可以看到,UT是修改了,但是该UT只是在原有UT的基础上简单的修改了一下,设置了一个Mock的UserService。并且该处的日期设定和系统约束不符合,修改日期应该是早于当日的一个日期。
这样的UT当然是不理想的,当需求变更时,UT有可能要重新设计,而不是在原来的基础上打补丁。简单的分析可以得出,应该有3个分支需要覆盖。
1 找不到userInfo的情况,该情况对应原有功能。
2 找到userInfo的一般情况,返回的结果列表包含多个list。
3 找到userInfo的特殊情况,用户的最后修改时间和结果的起始时间比较接近,导致结果为1个list的情况。原有的接口因为可以保证正确的实现只能产出30个不为null的日期组装的结果,因此没有考虑该情况。但是随着需求的变更,该特殊情况需要纳入考虑范围。
简单的一个修改如上,覆盖了3个主要的分支。
但是,修改完成后重新审视代码,发现还是存在一些明显的问题。
1该UT中有了重复的地方。
2主要的分支是覆盖了,但是没有考虑边界情况,即用户最后修改时间在起始时间之前。
3原有代码中,由于整数下标和Calendar中DAY_OF_WEEK的值不是对应的,因此需要转化,该处转化抽成一个小方法看上去比较好。
再次修改后代码如下:
有一个接口,原始定义和对应的UT如下:
/** * 构建一个按照自然周排好的日期列表(包括最近30天,不包含当日),周时间距离现在越近,在列表中越靠前。 * * <pre> * 保证每个子列表的大小都为7(一个星期的天数),没有日期则以null填充。 * * 例子: * 如果当前时间是2010-09-08(星期3)则构建的列表为: * 第1个subList 2010-09-06(星期1),2010-09-07(星期2),null,null,null,null,null, * 第2个subList 2010-08-30(星期1),2010-08-31(星期2),2010-09-01(星期3),2010-09-02(星期4),2010-09-03(星期5),2010-09-04(星期6),2010-09-05(星期日) * ... * 第n个subList null,null,null,null,date(星期5),date(星期6),date(星期日) * </pre> * * * @return 返回构建好的列表。 * */ public List<List<Date>> getDaysInWeekList();
private DateService dateService; @Before public void setUp() { dateService = new DateServiceImpl(); } @Test public void test() { List<List<Date>> list = dateService.getDaysInWeekList(); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, -30); int count = 0; for (int i = list.size() - 1; i >= 0; i--) { List<Date> subList = list.get(i); Assert.assertEquals(7, subList.size()); for (Date date : subList) { if (date == null) { continue; } else { Date tem = calendar.getTime(); Assert.assertEquals(DayUtil.getDayBeginString(tem), DayUtil.getDayBeginString(date)); calendar.add(Calendar.DATE, 1); count++; } } } Assert.assertEquals(30, count); }
当需求变更时,UT理应做出对应的修改。
新的需求比较简单。
新加入一个参数userId,通过该userId如果可以找到一个UserInfo的话,则返回结果的日期截至点为该UserInfo的最后修改日期。由其他系统保证该修改日期在当前时间之前的某一天。
新的UT如下:
private NewDateServiceImpl_0 newDateService; @Before public void initNewDateService() { newDateService = new NewDateServiceImpl_0(); newDateService.setUserService(new UserService() { @Override public UserInfo findUserInfo(String userId) { UserInfo userInfo = new UserInfo(); userInfo.setModifyDate(new Date()); return userInfo; } }); } @Test public void testGetDaysInWeekList() { List<List<Date>> list = newDateService.getDaysInWeekList("allen"); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, -30); int count = 0; for (int i = list.size() - 1; i >= 0; i--) { List<Date> subList = list.get(i); Assert.assertEquals(7, subList.size()); for (Date date : subList) { if (date == null) { continue; } else { Date tem = calendar.getTime(); Assert.assertEquals(DayUtil.getDayBeginString(tem), DayUtil.getDayBeginString(date)); calendar.add(Calendar.DATE, 1); count++; } } } Assert.assertEquals(30, count); }
可以看到,UT是修改了,但是该UT只是在原有UT的基础上简单的修改了一下,设置了一个Mock的UserService。并且该处的日期设定和系统约束不符合,修改日期应该是早于当日的一个日期。
这样的UT当然是不理想的,当需求变更时,UT有可能要重新设计,而不是在原来的基础上打补丁。简单的分析可以得出,应该有3个分支需要覆盖。
1 找不到userInfo的情况,该情况对应原有功能。
2 找到userInfo的一般情况,返回的结果列表包含多个list。
3 找到userInfo的特殊情况,用户的最后修改时间和结果的起始时间比较接近,导致结果为1个list的情况。原有的接口因为可以保证正确的实现只能产出30个不为null的日期组装的结果,因此没有考虑该情况。但是随着需求的变更,该特殊情况需要纳入考虑范围。
protected NewDateService newDateService; private void setUpUserService(final UserInfo userInfo) { newDateService.setUserService(new UserService() { @Override public UserInfo findUserInfo(String userId) { return userInfo; } }); } @Before public abstract void initNewDateService(); @Test public void testGetDaysInWeekListWithUserInfo_1() { final UserInfo userInfo = new UserInfo(); userInfo.setModifyDate(DayUtil.addDays(new Date(), -2)); newDateService.setUserService(new UserService() { @Override public UserInfo findUserInfo(String userId) { return userInfo; } }); List<List<Date>> list = newDateService.getDaysInWeekList("allen"); assertResult(list, 29); } @Test public void testGetDaysInWeekListWithUserInfo_2() { final UserInfo userInfo = new UserInfo(); userInfo.setModifyDate(DayUtil.addDays(new Date(), -28)); newDateService.setUserService(new UserService() { @Override public UserInfo findUserInfo(String userId) { return userInfo; } }); List<List<Date>> list = newDateService.getDaysInWeekList("allen"); assertResult(list, 3); } @Test public void testGetDaysInWeekListWithNull() { setUpUserService(null); List<List<Date>> list = newDateService.getDaysInWeekList("allen"); assertResult(list, 30); } private void assertResult(List<List<Date>> list, int expectedCount) { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, -30); int count = 0; for (int i = list.size() - 1; i >= 0; i--) { List<Date> subList = list.get(i); Assert.assertEquals(7, subList.size()); for (int k = 0; k < subList.size(); k++) { Date date = subList.get(k); if (date == null) { continue; } else { Date tem = calendar.getTime(); Assert.assertEquals(DayUtil.getDayBeginString(tem), DayUtil.getDayBeginString(date)); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); if (k != 6) { Assert.assertEquals(k + 2, dayOfWeek); } else { Assert.assertEquals(Calendar.SUNDAY, dayOfWeek); } calendar.add(Calendar.DATE, 1); count++; } } } Assert.assertEquals(expectedCount, count); }
简单的一个修改如上,覆盖了3个主要的分支。
但是,修改完成后重新审视代码,发现还是存在一些明显的问题。
1该UT中有了重复的地方。
2主要的分支是覆盖了,但是没有考虑边界情况,即用户最后修改时间在起始时间之前。
3原有代码中,由于整数下标和Calendar中DAY_OF_WEEK的值不是对应的,因此需要转化,该处转化抽成一个小方法看上去比较好。
再次修改后代码如下:
private final static int DAYS_OF_WEEK = 7; protected NewDateService newDateService; private void setUpUserService(final UserInfo userInfo) { newDateService.setUserService(new UserService() { @Override public UserInfo findUserInfo(String userId) { return userInfo; } }); } @Before public abstract void initNewDateService(); private void testGetDaysInWeekListWithUserInfo(int addDays, int expectedCount) { UserInfo userInfo = new UserInfo(); userInfo.setModifyDate(DayUtil.addDays(new Date(), addDays)); setUpUserService(userInfo); List<List<Date>> list = newDateService.getDaysInWeekList("allen"); assertResult(list, expectedCount); } @Test public void testGetDaysInWeekListWithUserInfoAll() { testGetDaysInWeekListWithUserInfo(-31, 0); for (int i = -30; i <= -1; i++) { testGetDaysInWeekListWithUserInfo(i, 31 + i); } } @Test public void testGetDaysInWeekListWithNull() { setUpUserService(null); List<List<Date>> list = newDateService.getDaysInWeekList("allen"); assertResult(list, 30); } private void assertResult(List<List<Date>> resultList, int expectedCount) { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, -30); int count = 0; for (int i = resultList.size() - 1; i >= 0; i--) { List<Date> weekList = resultList.get(i); Assert.assertEquals(DAYS_OF_WEEK, weekList.size()); for (int k = 0; k < weekList.size(); k++) { Date date = weekList.get(k); if (date != null) { Date tem = calendar.getTime(); Assert.assertEquals(DayUtil.getDayBeginString(tem), DayUtil.getDayBeginString(date)); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); Assert.assertEquals(convertIndexToDayOfWeek(k), dayOfWeek); calendar.add(Calendar.DATE, 1); count++; } } } Assert.assertEquals(expectedCount, count); } private int convertIndexToDayOfWeek(int index) { return (index + 1) % DAYS_OF_WEEK + 1; }
发表评论
-
实践中的重构32_使用标准的IO操作写法。
2012-07-14 18:42 1436看到这样一段代码,功能为读取一个指定文件的内容然后返回。 ... -
实践中的重构31_结果类两种实现的比较
2011-09-13 19:58 1094在查询接口结果类设计 ... -
实践中的重构30_不做油漆匠
2011-08-15 23:42 1297油漆匠的故事是编程文化中的一个著名故事。本地化如下。 小强毕业 ... -
实践中的重构29_不自动的自动化测试
2011-07-31 18:00 1068测试的精髓之一就是自 ... -
实践中的重构28_小心怀疑类库
2011-07-24 10:25 1070一般而言,类库的使用频率较高,场景较多,隐藏的bug就较少。 ... -
实践中的重构27_不要忘了内存空间
2011-06-06 18:31 1196方法在设计中,一般关注的是方法的功能契约,即方法需要什么样的参 ... -
实践中的重构26_奇怪的接口注释
2011-06-06 16:10 1361最近又看到奇怪的注释。 /** * 用户查询服务。 ... -
实践中的重构24_持续的方法重构
2011-05-01 02:20 1093很少有人可以一遍就写出好的代码。写代码和写文章差不多,大部分人 ... -
实践中的重构23_详尽的注释未必是好注释
2011-03-20 17:37 1552注释一直是软件开发中的一个老大难问题。 代码中一个注释都没有是 ... -
实践中的重构22_不要垃圾
2011-03-20 13:31 1068Java引入了GC当然很好,减轻了程序员手工管理内存的负担,但 ... -
实践中的重构21_给她一个好名字
2011-03-20 13:03 924名字的重要性实在是再怎么强调都不为过的。 为什么名字这么重要呢 ... -
实践中的重构20_一段可笑的异常处理逻辑
2011-03-06 20:32 1717Code review也是一个充满 ... -
实践中的重构19_脱裤子放屁
2011-03-03 23:17 2073每当看到代码中有一个 ... -
实践中的重构18_不对称的美
2011-02-26 22:30 997一般而言,自然界是以 ... -
实践中的重构17_表驱动法
2011-02-22 00:10 865代码以及初始的单元测试见 http://zhang-xzhi- ... -
实践中的重构16_多即是少
2011-01-16 23:44 1525在编写UT的过程中,随处可见重复,硬编码等等使得代码僵化的代码 ... -
实践中的重构15_null的意义和集合类作为方法结果类型
2011-01-12 22:16 654在编程中,估计null应该是一个很常写的词汇了。 实践中,经常 ... -
实践中的重构14_用方法设计保证正确性
2011-01-04 21:40 1025一般来说,方法的调用方遵循方法的契约调用某方法来完成某功能。每 ... -
实践中的重构13_利用递归提高代码的可维护性
2010-12-30 01:38 743有这么一段代码,是用来解析国内的地址信息的。 AddressI ... -
实践中的重构12_不要乱用异常
2010-12-30 00:36 1534code review的时候,发现了如下代码。 /** ...
相关推荐
描述中的“幅值谱重构语音”指的是从MFCC中恢复出幅度谱,然后使用IFFT将其转换回时间序列。 **谱重构**是指根据频率域信息(如幅度谱或功率谱)重建原始信号的过程。在语音处理中,谱重构对于语音识别、语音合成...
在描述中提到的"对经验模态分解后的各分量IMF进行重构代码,函数可直接调用",意味着这个压缩包中包含了一个名为"EMDchonggou.m"的MATLAB脚本文件,该文件提供了实现IMF重构功能的代码。用户可以直接运行这个函数,...
标题中的“用于信号的EMD、EEMD、VMD分解_vmd重构_故障诊断emd_故障诊断_故障重构_VMD信号重构_源码.rar.rar”揭示了该压缩包文件包含的是与信号处理相关的源代码,特别是涉及了三种重要的信号分解方法:Empirical ...
《重构:改善既有代码设计》是一本由Martin Fowler所著的经典IT著作,它详细阐述了在软件开发过程中如何通过重构来提升代码质量、可读性和维护性。重构是一种系统性的方法,旨在不改变软件外在行为的前提下,改进其...
在本文中,我们将深入探讨基于Matlab的压缩感知(Compressive Sensing,简称CS)重构算法的实现。压缩感知是一种理论先进的信号处理...在实际项目中,还需要结合具体应用场景,不断优化算法,以达到最佳的重构效果。
配电网重构是电力系统领域中的一个重要研究课题,它涉及到电力系统的稳定运行与经济效率。配电网重构的目标是在满足一系列约束条件下,通过改变开关状态,优化网络结构,以达到提高供电可靠性、降低运营成本、改善...
资源名:用于信号的EMD、EEMD、VMD分解_vmd重构_故障诊断emd_故障诊断_故障重构_VMD信号重构 资源类型:matlab项目全套源码 源码介绍:用于信号的分解、降噪和重构,实现故障诊断 源码说明: 全部项目源码都是经过...
经验模态分解(Empirical Mode Decomposition,简称EMD)是一种强大的数据分析技术,尤其...通过对这些资源的深入理解和实践,我们可以更好地掌握EMD技术,并将其应用到实际问题中,实现非平稳信号的有效分析和重构。
这个压缩包中的"第13章 MATLAB图像重构实战"可能包含了一系列的MATLAB脚本和函数,用于演示如何使用MATLAB实现fanbeam变换。这些脚本可能包括数据读取、预处理、fanbeam投影、反投影以及图像重构等步骤。在学习和...
在IT行业中,尤其是在医疗影像处理领域,三维重构技术扮演着至关重要的角色。"NewPrjName.rar" 是一个与三维医学图像重构相关的项目文件压缩包,它涉及到的是使用C++编程语言来实现这一复杂的计算过程。这个项目的...
在电力系统领域,配电网重构是一项关键的技术,其目的是通过改变配电网络的...总之,配电网重构源码的获取为研究和实践提供了宝贵的工具,通过深入学习和应用,可以提升电力系统的运行效率,为智能电网的发展做出贡献。
牛顿拉普逊法就算配电网重构的潮流程序,结构清晰易懂。
压缩传感重构算法中的子空间追踪算法,用于信号的重构
在本项目中,作者计算了重构图像与原始图像的误差,这是评估重构质量的重要指标。通常使用的误差度量有均方误差(Mean Square Error, MSE)、峰值信噪比(Peak Signal-to-Noise Ratio, PSNR)等。MSE是衡量两个图像...
重构__改善既有代码的设计_高清 绝对清晰
在IT领域,稀疏重构算法是信号处理和数据科学中的一个重要概念,特别是在压缩感知理论(Compressive Sensing, CS)中。压缩感知是一种革命性的理论,它表明,如果一个信号可以用较少的非零元素(即稀疏表示)来描述...
在IT行业中,动态重构是一种先进的软件工程实践,它允许开发者在程序运行时对代码结构进行修改,以提高软件性能、可维护性和可扩展性。在标题"top.rar_动态重构_动态可重构_动态重构"中,我们可以推断这是一个关于...