浏览 1425 次
锁定老帖子 主题:实践中的重构25_UT也需要持续重构
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-05-01
有一个接口,原始定义和对应的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; } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |