7

我正在使用easymock 模拟一个在其主体中有日期的方法,如下所示:

public void testedMethod() {
    ...
    if (doSomething(new Date())) {
    ...
}

我的测试看起来像这样:

public void testThatMethod() {
    ...
    expect(testedClass.testedMethod(new Date())).andReturn(false);
    ...
}

但是当我运行测试时,有时会出现这样的错误:

意外的方法调用测试方法(2010 年 1 月 28 日星期四 09:45:13 GMT-03:00):测试方法(2010 年 1 月 28 日星期四 09:45:13 GMT-03:00):预期:1,实际:0

我认为这是因为有时日期略有不同。我已经尝试了一些灵活的期望,但没有成功。有没有办法解决这个问题?

4

6 回答 6

5

我们经常面临类似的问题,这些是我看到的替代方案:

  1. 将日期作为参数提供给方法 (+) 快速更改 (-) 有点脏——当你只想使用“现在”时,它也会污染你的界面
  2. 从合作者“QueryCurrentDateProvider”中提取日期(+)仍然很快(+)也可以被嘲笑->您确定您使用相同的日期(-)为您需要做类似事情的每个服务创建的不必要的合作者
  3. 编写您自己的 EasyMock 参数匹配器,在其中抽象出您实际想要做的事情 - 当您只对当天感兴趣时,而不是您可以使用 commons DateUtils.isSameDay 之类的东西来让它运行(+)最干净的解决方案( +) 无需更改您的生产代码 (-) 您必须编写自己的匹配器(尽管我不明白为什么 EasyMock 还没有)
  4. 将“new Date()”移动到私有方法,然后使用类似 PowerMock (+) quick (+) 对生产代码的小改动 (-) 引入 power mock 作为依赖项来模拟此方法
  5. 将参数从 Date 更改为 String 并使用通用模式在调用方法之前将日期转换为字符串 (+) 快速 (+) 无需额外代码,测试站点上所需的库 (-) 您必须格式化日期在调用方法并解析被调用方法中的日期之前

所以这真的取决于你的个人喜好。当您经常使用当前时间戳时,我会推荐参数匹配器 - 因为这项投资将很快得到回报。

于 2012-05-09T14:54:22.627 回答
4

停止使用 new Date(),改用具有恒定时间的日历。

//Declare the Calendar in your test method
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0l);

//receive the calendar to be used in testedClass constructor
public void testedMethod() {
    ...
    if (doSomething(cal.getTime())) {
    ...
}

//use the same calendar to make the assertion
public void testThatMethod() {
    ...
    expect(testedClass.(testedMethod(cal.getTime())).andReturn(false);
    ...
}
于 2010-01-28T17:55:20.703 回答
3

我刚刚找到了这个线程,它帮助我解决了一个我被困了一个小时的问题。

以为我会分享我的 2 美分:

如果您不关心日期值并且只想知道它是一个 Date 对象,只需使用 EasyMock 的预定义匹配器:

EasyMock.expect(objectMock.isPollingTimeOut(EasyMock.eq(600000L), EasyMock.isA(Date.class), EasyMock.eq(someMock))).andReturn(false);

请记住,一旦您使用了匹配器,您就必须像我所做的那样对您正在测试的方法中的所有参数使用匹配器。

于 2012-09-28T07:32:56.600 回答
2

如果您能准确找出失败的原因,您可以编写自己的匹配器以更灵活地匹配日期。请参阅匹配器部分http://easymock.org/EasyMock2_2_Documentation.html

于 2010-01-28T14:26:38.047 回答
2

可能是日期的毫秒部分不同。Calendar.set()在创建日期对象之前,您可能需要将其归零:

Calendar myCalendar = Calendar.getInstance();
myCalendar.set(Calendar.MILLISECOND, 0);
Date testDate = myCalendar.getTime();

但这是一个猜测:)

于 2010-01-28T14:28:48.357 回答
0

使用自定义 EasyMock Matcher 进行松散的日期比较。这是一个示例,它将检查日期是否在彼此的一秒内。

public class MyEasyMockMatchers {

    public static Date withinSecondOf(Date value){
        EasyMock.reportMatcher(new IArgumentMatcher() {
            @Override
            public boolean matches(Object argument) {
                return argument instanceof Date
                        && Math.abs(((Date) argument).getTime() - value.getTime()) < Timer.ONE_SECOND;
            }

            @Override
            public void appendTo(StringBuffer buffer) {
                buffer.append(value.toString());
            }
        });
        return null;
    }
}

然后在您的测试中使用:

import static my.package.MyEasyMockMatchers.*;
...
expect(testedClass.testedMethod(withinSecondOf(new Date())))
        .andReturn(false);

请注意,当您使用一个匹配器时,您必须对整个期望使用匹配器。例如:

expect(testedClass.testedMethod(42, "hello", new Date()))
        .andReturn(false);
// becomes
expect(testedClass.testedMethod(eq(42), eq("hello"), withinSecondOf(new Date())))
        .andReturn(false);

请参阅:https ://easymock.org/user-guide.html#verification-expectations

于 2020-06-24T16:57:04.890 回答