为什么这个与 Joda-Time 相关的测试有时会失败?
Why does this Joda-Time related test fail sometimes?
我有一个 class,我在其中计算当前日期 (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 在本地重建代码时,测试没有失败。
什么可能导致这种奇怪的行为?
更新一:错误信息为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 个。
您应该从 Logic
class 中删除 java.util.Date
并且只在此处使用 joda classes。这将使您的代码更加清晰,因为不需要在 LocalDate
和 Date
之间进行转换。实际上这样做会使您的测试变得毫无意义,因为您只会测试 Years.yearsBetween
的 joda 时间,我希望它已经被测试过。
我怀疑该错误可能与您的 LocalDate
/Date
转换有关,您应该通过将 now.toDate()
和 birthDay1.toDate()
的实际值打印到测试日志。并查看 LocalDate.toDate:
的 javadoc
Converting to a JDK Date is full of complications as the JDK Date
constructor doesn't behave as you might expect around DST transitions.
This method works by taking a first guess and then adjusting the JDK
date until it has the earliest valid instant. This also handles the
situation where the JDK time zone data differs from the Joda-Time time
zone data.
Joda-Time 是正确的 请牢记您的代码:
您已将 birthDay2
明确设置为 2008-08-27。而您的 now-variable 是日期 2015-08-28。因此,如果您将 birthDay2
加 7 年,您将得到日期 2015-08-27,它仍然比 2015-08-28 早一天。
如果你有now=2015-08-27(那么正好相差7年),7年的结果不会改变。
6 年的预期只有在您将 birthDay2
设置为 2008-08-28 和现在=2015-08-27 时才正确(因为这里的日期比较会阻止完整的 7 -年增量)。
小旁注:
关于闰日有一个特殊情况需要注意(这里我认为 Joda-Time 是错误的)- 另请参阅此关闭 issue。
我有一个 class,我在其中计算当前日期 (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 在本地重建代码时,测试没有失败。
什么可能导致这种奇怪的行为?
更新一:错误信息为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 个。
您应该从 Logic
class 中删除 java.util.Date
并且只在此处使用 joda classes。这将使您的代码更加清晰,因为不需要在 LocalDate
和 Date
之间进行转换。实际上这样做会使您的测试变得毫无意义,因为您只会测试 Years.yearsBetween
的 joda 时间,我希望它已经被测试过。
我怀疑该错误可能与您的 LocalDate
/Date
转换有关,您应该通过将 now.toDate()
和 birthDay1.toDate()
的实际值打印到测试日志。并查看 LocalDate.toDate:
Converting to a JDK Date is full of complications as the JDK Date constructor doesn't behave as you might expect around DST transitions. This method works by taking a first guess and then adjusting the JDK date until it has the earliest valid instant. This also handles the situation where the JDK time zone data differs from the Joda-Time time zone data.
Joda-Time 是正确的 请牢记您的代码:
您已将 birthDay2
明确设置为 2008-08-27。而您的 now-variable 是日期 2015-08-28。因此,如果您将 birthDay2
加 7 年,您将得到日期 2015-08-27,它仍然比 2015-08-28 早一天。
如果你有now=2015-08-27(那么正好相差7年),7年的结果不会改变。
6 年的预期只有在您将 birthDay2
设置为 2008-08-28 和现在=2015-08-27 时才正确(因为这里的日期比较会阻止完整的 7 -年增量)。
小旁注:
关于闰日有一个特殊情况需要注意(这里我认为 Joda-Time 是错误的)- 另请参阅此关闭 issue。