为什么这个与Joda-Time相关的测试有时会失败?

时间:2015-08-31 11:40:12

标签: java jodatime

我有一个班级,我计算当前日期(now)和其他日期(birthday)之间的年份差异:

import java.util.Date;

import org.joda.time.LocalDate;
import org.joda.time.Years;

public class Logic {
    private final Date now;

    public Logic(final Date curDate) {
        now = curDate;
    }

    [...]

    protected int getAgeInYears(final Date now, final Date birthday) {
        final LocalDate nowDate = new LocalDate(now.getTime());
        final LocalDate birthdayDate = new LocalDate(birthday.getTime());
        return Years.yearsBetween(birthdayDate, nowDate).getYears();
    }
}

然后我有一个单元测试,它验证getAgeInYears

public class SomeTest {
    @Test
    public void test() {
        final LocalDate now = new LocalDate(2015, 8, 28);
        final Logic objectUnderTest =
            new Logic(now.toDate());
        final LocalDate birthDay1 = new LocalDate(2015 - 7, 8, 28);
        Assert.assertEquals(6,
            objectUnderTest.getAgeInYears(now.toDate(), birthDay1.toDate())); // This assertion fails sometimes, but not always
        final LocalDate birthDay2 = new LocalDate(2015 - 7, 8, 27);
        Assert.assertEquals(7,
            objectUnderTest.getAgeInYears(now.toDate(), birthDay2.toDate()));
        final LocalDate birthDay3 = new LocalDate(1981, 4, 24);
        Assert.assertEquals(34,
            objectUnderTest.getAgeInYears(now.toDate(), birthDay3.toDate()));

    }
}

断言

Assert.assertEquals(6, 
    objectUnderTest.getAgeInYears(now.toDate(), birthDay1.toDate()));

有时会失败。

在我的机器上,测试运行没有错误。在其中一个测试失败的构建服务器(Java 6)上。当我使用Java 6在本地重建代码时,测试没有失败。

什么可能导致这种奇怪的行为?

更新1:错误消息为expected:<6> but was:<7>

更新2:我重写了代码以摆脱toDate来电并得到了这个:

public class Logic {
    private final LocalDate now;

    public Logic(final LocalDate curDate) {
        now = curDate;
    }

    [...]

    protected int getAgeInYears(final LocalDate now, final LocalDate birthday) {
        final LocalDate nowDate = new LocalDate(now);
        final LocalDate birthdayDate = new LocalDate(birthday);
        return Years.yearsBetween(birthdayDate, nowDate).getYears();
    }
}

public class LogicTest {
    @Test
    public void getAgeInYearsSunnyDay() {
        final LocalDate now = new LocalDate(2015, 8, 28);
        final AdditionalServicesLogic objectUnderTest =
            new AdditionalServicesLogic(now);
        final LocalDate birthDay1 = new LocalDate(2015 - 7, 8, 28);
        Assert.assertEquals(7,
            objectUnderTest.getAgeInYears(now, birthDay1));
        final LocalDate birthDay2 = new LocalDate(2015 - 7, 8, 27);
        Assert.assertEquals(6,
            objectUnderTest.getAgeInYears(now, birthDay2));
        final LocalDate birthDay3 = new LocalDate(1981, 4, 24);
        Assert.assertEquals(34,
            objectUnderTest.getAgeInYears(now, birthDay3));

    }
}

现在我经常在线上获得断言错误

Assert.assertEquals(6,
    objectUnderTest.getAgeInYears(now, birthDay2));

我希望得到6,但得到7。

2 个答案:

答案 0 :(得分:1)

您应该从java.util.Date课程中删除Logic,并在此处仅使用joda课程。这将使您的代码更加清晰,因为无需在LocalDateDate之间进行转换。实际上这样做会让你的测试变得毫无意义,因为你只会测试joda时间的Years.yearsBetween,我希望它已经被测试了。

我怀疑该错误可能在您的LocalDate / Date转换时出现,您应该通过将now.toDate()birthDay1.toDate()的实际值打印到测试日志来检查。并查看LocalDate.toDate的javadoc:

  

转换为JDK日期与JDK日期一样充满复杂性   构造函数不像DST转换那样表现。   此方法通过先猜测然后调整JDK来工作   日期,直到它有最早的有效时刻。这也处理了   JDK时区数据与Joda-Time时间不同的情况   区域数据。

答案 1 :(得分:1)

Joda-Time是正确的记住您​​的代码:

您已明确将birthDay2设置为2008-08-27。你现在变量是2015-08-28的日期。因此,如果您在birthDay2添加7年后,您将获得2015-08-27的日期,该日期仍比2015-08-28早一天。

如果您现在= 2015-08-27(那么差异恰好是7年),7年的结果将不会改变。

如果您将birthDay2设置为2008-08-28而现在= 2015-08-27(因为这里的日期比较可以防止完整的7年),那么期望6年是正确的-delta)。

小旁注:

闰日有一个特殊情况,需要一些关注(这里我认为Joda-Time是错误的) - 请参阅此关闭的issue