2010-12-15 53 views
20

我想测试这种方法:如何模拟JodaTime的实际日期?

public FirmOrder findActiveByModelColor(ModelColor modelColor) { 
    Query query = em.createQuery("FROM FirmOrder fo WHERE fo.modelColor = :modelColor AND fo.year = :year AND fo.month = :month"); 
    query.setParameter("modelColor", modelColor); 
    query.setParameter("year", new DateTime().year().get()); 
    query.setParameter("month", new DateTime().monthOfYear().get()); 
    return (FirmOrder) query.getSingleResult(); 
} 

但我需要DateTime().year().get()DateTime().dayOfMonth().get()总是返回相同的日期

TKS

回答

48

如果您无法按照skaffman的建议添加工厂对象,则可以使用DateTimeUtils.setCurrentMillisFixed()

+7

评论真好,我想两次。 – 2012-05-16 00:19:29

+5

也许你会想在测试断言后用'setCurrentMillisSystem'将它重置回系统。 – 2014-03-18 06:19:25

+6

该API修改了全局变量,因此必须避免。 – 2014-08-02 15:59:56

14

然后,你需要定义一个Clock接口,并注入到您的班级

public interface Clock { 
    DateTime getCurrentDateTime(); 
} 

then:

Clock clock; 

public FirmOrder findActiveByModelColor(ModelColor modelColor) { 
    Query query = em.createQuery("FROM FirmOrder fo WHERE fo.modelColor = :modelColor AND fo.year = :year AND fo.month = :month"); 
    query.setParameter("modelColor", modelColor); 
    query.setParameter("year", clock.getCurrentDateTime().year().get()); 
    query.setParameter("month", clock.getCurrentDateTime().dayOfMonth().get()); 
    return (FirmOrder) query.getSingleResult(); 
} 

然后,您的测试可以注入执行Clock(例如,使用模拟框架)总是返回一个固定的时间。

我使用Clock接口很多我自己的东西,我仍然感到惊讶,它不是其中一个共同的图书馆的一部分。我有两个实现我使用了很多,WallClockStoppedClock(这对于使用固定时间的测试非常有用)。

+0

我喜欢你的想法。但我有夫妻问题,我想问。 'Clock#getCurrentDateTime()'会返回当前的'JodaTime#DateTime',这非常棒。不过,我需要将当前的DateTime与美国东部时间下午4点进行比较。在我的代码中,我有这个'fourPM = new DateTime(current.getYear(),current.getMonthOfYear(), \t \t \t \t current.getDayOfMonth(),16,0,0,0,DateTimeZone.forID “));'for'current = new DateTime()' – 2011-05-18 18:00:52

+0

@Harry:您需要提出一个新问题 – skaffman 2011-05-18 18:04:17

+0

我刚刚创建了一个新问题。 http://stackoverflow.com/questions/6049777/mockito-how-to-mock-an-interface-of-jodatime请帮忙 – 2011-05-18 19:05:59

1

这很容易,如果使用的是JMockit期望嘲讽API:

@Test 
public void findActiveByModelColor() 
{ 
    new NonStrictExpectations() 
    { 
     @Cascading DateTime dt; 

     { 
      dt.year().get(); result = 2010; 
      dt.monthOfYear().get(); result = 12; 
     } 
    }; 

    FirmOrder fo = testedObject.findActiveByModelColor(modelColor); 

    // asserts... 
} 
+1

JMockit擅长测试写得不好的代码。 – IAdapter 2010-12-16 19:35:25

+0

因此,使用'DateTime'(或'java.util.Date')这样的代码总是不好?使用Apache Commons Email API的代码怎么样,它实例化一个SimpleEmail对象并在其上调用send()?它是不好的代码?为什么? – 2010-12-17 18:41:49

4

貌似唯一的选择是使用应答功能发布此评论:

代码的以下部分可导致到难以检测错误:

query.setParameter("year", new DateTime().year().get()); 
query.setParameter("month", new DateTime().monthOfYear().get()); 

让我们假设塔今天是2011年的最后一天,这部分代码被称为纳米1秒在新的一年之前,第一个声明需要超过1纳秒才能完成。这意味着,今年将设定为2011年,但月份为1,但最好到2011/12或2012/1。

虽然在统计上是非常不可能发生的,但在逻辑上有可能发生:)

您应该创建一个DateTime实例,并用它来填充两个yearmonth

+1

好吧,这不是OP的答案,但我赞成它,因为更多的人需要意识到这个问题。 鉴于许多企业商店(和家庭设置)在晚上的下班时间(如下午11:30)进行编译,这个错误实际上非常普遍 - 并且很烦人。它通常更加微妙,但这就是为什么在另一个答案中提到的StoppedClock是一个好主意。 – 2012-05-16 00:18:05