用Java测试基于时间的逻辑单元

我有一个方法,根据当前日期的不同,对从DB中提取的数据实现不同的逻辑。

我想通过让unit testing创​​建对象来测试它,将它们保存在DB中并调用测试的方法。 但是,为了获得可预测的结果,我每次都需要更改系统日期,而且我不知道如何在Java中执行此操作。

建议?

您可以使用当前日期生成预期结果。

或者你编写你的系统来使用你在测试时给它的日期/时间(而不是时钟)这样的时间总是测试期望的。

我喜欢用的东西

 interface TimeSource { long currentTimeMS(); // actually I have currentTimeNS void currentTimeMS(long currentTimeMS); } enum VanillaTimeSource implements TimeSource { INSTANCE; @Override public long currentTimeMS() { return System.currentTimeMillis(); } @Override public void currentTimeMS(long currentTimeMS) { // ignored } } class FixedTimeSource implements TimeSource { private long currentTimeMS; @Override public long currentTimeMS() { return currentTimeMS; } @Override public void currentTimeMS(long currentTimeMS) { this.currentTimeMS = currentTimeMS; } } 

在测试中,我使用FixedTimeSource,它可以是数据驱动的,例如由输入/事件设置。 在生产中我使用VanillaTimeSource.INSTANCE忽略输入/事件中的时间并使用当前时间。

你需要考虑在课堂上注入一些东西,让你自定义时间的呈现方式。

例如

 public interface TimeProvider { DateTime getCurrentTime(); } public class UnderTest { // Inject this in some way (eg provide it in the constructor) private TimeProvider timeProvider; public void MyMethod() { if (timeProvider.getCurrentTime() == "1234") { // Do something } } } 

现在,在您的unit testing中,您可以提供时间提供程序的虚假实现。 在实际生产代码中,您只需返回当前日期时间即可。

我最近遇到了类似的问题代码我无法重构太多(时间限制,不想无意中破坏任何东西)。 它有一个我想测试的方法,它调用System.currentTimeMillis(),我想测试的情况取决于返回的值。 就像是:

 public class ClassINeedToTest { public boolean doStuff() { long l = System.currentTimeMillis(); // do some calculation based on l // and return the calculation } } 

为了允许unit testing,我重构了类,因此它有一个受保护的辅助方法

 protected long getCurrentTimeMillis() { // only for unit-testing purposes return System.currentTimeMillis(); } 

这个方法是由doStuff()调用的。 这并没有改变function,但现在意味着当我在unit testing中调用它时,我可以覆盖它以返回特定值,如

 ClassINeedToTest testClass = new ClassINeedToTest() { protected long getCurrentTimeMillis() { // return specific date for my test return 12456778L; } }; boolean result = testClass.doStuff(); // test result with an assert here 

但这确实意味着我污染了我class级的界面,所以你可能会认为成本太高了。 如果你可以更多地重构代码,可能有更好的方法。