使用Guava Supplier Mock Datetime

通过下面的例子了解Guava Supplier的用法.在做单元测试的时候, 我们可能需要Mock掉一些对外部资源的依赖. 比如时间, 随机数, 系统文件访问.

下面是将要测试的代码, 将当前时间输出:
@Controller
@RequestMapping(value = "/time")
@VisibleForTesting
class TimeController {
 
	@RequestMapping(value = "/current", method = RequestMethod.GET)
	@ResponseBody
	public String showCurrentTime() {
		// BAD!!! Can't test
		DateTime 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 somewhere
		String firstName = UserUtilities.getUser().getFirstName();
		// more Guava
		if(isNullOrEmpty(firstName)) {
			value = DEFAULT_NAME;
		} else {
			value = firstName;
		}
	}
	 
	@Override
	public String get() {
		return value;
	}
}


通过上面的代码你将不再关心firstName是什么, 只需要调用get方法即可.


对目标代码进行重构

实现一个DateTime Supplier. 同时提供一个接口, 方便测试:
public interface DateTimeSupplier extends Supplier<DateTime> {
	DateTime get();
}


下面是具体实现
public class DateTimeUTCSupplier implements DateTimeSupplier {
	@Override
	public DateTime get() {
		return new DateTime(DateTimeZone.UTC);
	}
}


然后注入DateTimeSupplier:
@Controller
@RequestMapping(value = "/time")
@VisibleForTesting
class TimeController {
 
	@Autowired
	@VisibleForTesting
	// Injected DateTimeSupplier
	DateTimeSupplier dateTime;
	 
	@RequestMapping(value = "/current", method = RequestMethod.GET)
	@ResponseBody
	public 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;
	}
	 
	@Override
	public DateTime get() {
		return mockedDateTime;
	}
}


最后是测试代码:
public class TimeControllerTest {
 
	private final int HOUR_OF_DAY = 12;
	private final int MINUTE_OF_DAY = 30;
	 
	@Test
	public void testShowCurrentTime() throws Exception {
		TimeController controller = new TimeController();
		// Create the mock DateTimeSupplier with our known DateTime
		controller.dateTime = new MockDateTimeSupplier(new DateTime(2012, 1, 1, HOUR_OF_DAY, MINUTE_OF_DAY, 0, 0));
		 
		// Call our method
		String dateTimeString = controller.showCurrentTime();
		 
		// Using hamcrest for easier to read assertions and condition matchers
		assertThat(dateTimeString, is(String.format("%d:%d", HOUR_OF_DAY, MINUTE_OF_DAY)));
}
 
}


总体感觉代码还是比较多的, 又是接口又是实现的. 而目标就是为了对系统时间进行mock, 不过提供了一种单元测试的思路.

原文: http://java.dzone.com/articles/mocking-jodatimes-datetime-and

你可能感兴趣的:(guava,单元测试,mock,unit test)