使用Guava Supplier Mock Datetime
通过下面的例子了解Guava Supplier的用法.在做单元测试的时候, 我们可能需要Mock掉一些对外部资源的依赖. 比如时间, 随机数, 系统文件访问.
下面是将要测试的代码, 将当前时间输出:
@Controller@RequestMapping(value = "/time")@VisibleForTestingclass TimeController { @RequestMapping(value = "/current", method = RequestMethod.GET)@ResponseBodypublic String showCurrentTime() {// BAD!!! Can't testDateTime dateTime = new DateTime();return DateTimeFormat.forPattern("hh:mm").print(dateTime);}}但是这里有一个问题, 就是代码中是直接new的一个DateTime对象, 所以造成了对系统时间的直接依赖. 导致我们对输出时间的测试比较困难, 因此这里我们要借助Guava Supplier.
Supplier只有一个方法: get(), 返回suppiler构建的对象. 比如下面的例子:
public class FirstNameSupplier implements Supplier<String> { private String value;private static final String DEFAULT_NAME = "GUEST"; public FirstNameSupplier() {// Just believe that this goes and gets a User from somewhereString firstName = UserUtilities.getUser().getFirstName();// more Guavaif(isNullOrEmpty(firstName)) {value = DEFAULT_NAME;} else {value = firstName;}} @Overridepublic String get() {return value;}}通过上面的代码你将不再关心firstName是什么, 只需要调用get方法即可.
对目标代码进行重构
实现一个DateTime Supplier. 同时提供一个接口, 方便测试:
public interface DateTimeSupplier extends Supplier<DateTime> {DateTime get();}下面是具体实现
public class DateTimeUTCSupplier implements DateTimeSupplier {@Overridepublic DateTime get() {return new DateTime(DateTimeZone.UTC);}}然后注入DateTimeSupplier:
@Controller@RequestMapping(value = "/time")@VisibleForTestingclass TimeController { @Autowired@VisibleForTesting// Injected DateTimeSupplierDateTimeSupplier dateTime; @RequestMapping(value = "/current", method = RequestMethod.GET)@ResponseBodypublic String showCurrentTime() {return DateTimeFormat.forPattern("hh:mm").print(dateTime.get());}}创建一个MockDateTimeSupplier用来做测试:
public class MockDateTimeSupplier implements DateTimeSupplier { private final DateTime mockedDateTime; public MockDateTimeSupplier(DateTime mockedDateTime) {this.mockedDateTime = mockedDateTime;} @Overridepublic DateTime get() {return mockedDateTime;}}最后是测试代码:
public class TimeControllerTest { private final int HOUR_OF_DAY = 12;private final int MINUTE_OF_DAY = 30; @Testpublic void testShowCurrentTime() throws Exception {TimeController controller = new TimeController();// Create the mock DateTimeSupplier with our known DateTimecontroller.dateTime = new MockDateTimeSupplier(new DateTime(2012, 1, 1, HOUR_OF_DAY, MINUTE_OF_DAY, 0, 0)); // Call our methodString dateTimeString = controller.showCurrentTime(); // Using hamcrest for easier to read assertions and condition matchersassertThat(dateTimeString, is(String.format("%d:%d", HOUR_OF_DAY, MINUTE_OF_DAY)));} }总体感觉代码还是比较多的, 又是接口又是实现的. 而目标就是为了对系统时间进行mock, 不过提供了一种单元测试的思路.
原文: http://java.dzone.com/articles/mocking-jodatimes-datetime-and