欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用Guava Supplier Mock Datetime

程序员文章站 2022-04-07 12:27:38
...
通过下面的例子了解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