2012-02-23 99 views
8

我有一种方法,根据当前日期是从数据库中获取的数据实现不同的逻辑。Java中的单元测试基于时间的逻辑

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

对此提出建议?

+2

改变你的方法,这样你的确可以把时间作为参数,那么你可以通过给你任何你想要的时间来测试它。这又是什么话? – belgther 2012-02-23 09:19:26

+0

你能告诉你如何得到当前的日期和时间?也许嘲笑会起作用... – 2012-02-23 09:22:15

+0

现在只需用'new Date()',也许我需要一个TimeProvider类 – Alex 2012-02-23 09:43:41

回答

14

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

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

我使用类似

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,它忽略输入/事件中的时间并使用当前时间。

+0

第一个建议可能赢了没有工作。我也应该提到,准确提取的数据也是基于日期(根据某一列)。这意味着即使逻辑没有什么不同,我也不得不根据一年中的每一天生成不同的结果。我可能会提出第二个建议 – Alex 2012-02-23 09:32:03

+0

在检查结果之前,您可以生成预期结果作为运行测试的一部分。你不需要提前生成它们。 – 2012-02-23 09:34:11

+0

实际上,将接收时间的类/组件作为参数确保它是一个很好的组件,因为它可以从系统时间中解耦。您将所有应用程序特定的配置(“使用系统时间”)放在组件外。它只需要依靠外部可配置的刺激。 – helios 2012-02-23 09:46:27

8

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

例如

public interface TimeProvider { 
    DateTime getCurrentTime(); 
} 

public class UnderTest { 

    // Inject this in some way (e.g. provide it in the constructor) 
    private TimeProvider timeProvider; 

    public void MyMethod() { 
    if (timeProvider.getCurrentTime() == "1234") { 
     // Do something 
    } 
    } 
} 

现在在单元测试中,你可以提供假的实施时间提供商。在实际生产代码中,您可以返回当前日期时间。

+0

当然,你也可以提供它作为'belgther'建议的参数:) – 2012-02-23 09:20:52

2

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

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

为了让单元测试,我重构了类,所以它有其保护

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

一个辅助方法,该方法是由doStuff称为()。这并没有改变的功能,但现在的意思是,当我把它的单元测试,然后我可以重写此方法以返回一个特定的值,例如

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 

然而,这意味着我已经污染了我的班级的界面,所以你可能会决定成本太高。如果你可以更多地重构代码,可能会有更好的方法。