单元测试在一个完整的软件开发流程中是必不可少的、非常重要的一个环节。通常写单元测试并不难,但有的时候,有的代码和功能难以测试,导致写起测试来困难重重。所以写出的代码具有可测试性,具有很重要的作用。
通常一个单元测试主要有三个行为:
- 初始化需要测试的模块或方法。
- 调用方法。
- 观察结果(断言)
这三个行为分别被称为Arrange, Act and Assert。
@Test public void isPalindrome() { //初始化:初始化需要被测试的模块,这里就是一个对象。 //也可能没有初始化模块,例如测试一个静态方法。 PalindromeDetector detector = new PalindromeDetector(); //调用方法:记录返回值,以便后续验证。 //如果方法无返回值,那么我们需要验证它在执行过程中是否对系统的其他部分造成了影响,或产生了副作用。 boolean isPalindrome = detector.isPalindrome("kayak"); //断言:验证返回结果是否和预期一致。 Assert.assertTrue(isPalindrome); }
需求是在夜晚触摸到台灯时自动开灯。可以通过对当前时间的获取来获得结果
public static String getTimeOfDay() { Calendar calendar = GregorianCalendar.getInstance(); calendar.setTime(new Date()); int hour = calendar.get(Calendar.HOUR_OF_DAY); if (hour >= 0 && hour < 6) { return "Night"; } if (hour >= 6 && hour < 12) { return "Morning"; } if (hour >= 12 && hour < 18) { return "Afternoon"; } return "Evening";}
如果我们以单元测试的角度来看,就会发现这段代码根本无法编写测试, newdata()代表当前时间,这是一个内嵌在方法里的隐含输入,这个输入是随时变化的,不同时间运行这个方法,返回的值也会不同。这个方法的不可预测性导致了无法测试。如果要测试,我们的测试代码可能要这样写:
@Test public void getTimeOfDayTest() { try { // 修改系统时间,设为6点 ... String timeOfDay = getTimeOfDay(); Assert.assertEquals("Morning", timeOfDay); } finally { // 恢复系统时间 ... } }