2016-01-05 2 views
3

У меня есть класс Util с 1 методами, который вычисляет возраст с помощью Joda времени:время независимого JUnit Test Cases

public static int getAge(LocalDate birthdate) { 
    LocalDate today = new LocalDate(); 
    Period period = new Period(birthdate, today, PeriodType.yearMonthDay()); 
    return period.getYears(); 
} 

я написал обширный класс теста JUnit, но как я могу сделать это не зависит от времени ? Если я создам тестовый пример, чтобы рассчитать возраст кого-то, если они родились сегодня в 1970 году, тогда результат будет 46 лет. Но через 1 год, если я запустил тестовый пример, он потерпит неудачу, потому что результат будет равен 47.

Так как же сделать эти тестовые случаи независимыми от времени. Я думал о наличии какого-то интерфейса календаря, из которого тестовые примеры будут создавать объект даты. Я также наткнулся на сообщение this, которое является еще одним возможным решением этого, но я не уверен, как это сделать.

ответ

2

Использование фиксированной даты:

LocalDate today = new LocalDate(2016, 1, 5); 
+0

Ничего себе .... Я не уверен, почему я не думал об этом ...... наиболее очевидное решение ... спасибо – Richard

+1

np. Вы можете принять ответ :-) – mks

+0

На самом деле это не работает сейчас, когда я думаю об этом, потому что 'new LocalDate' находится внутри функции getAge, и я не могу его жестко кодировать. Это должна быть текущая дата, когда она используется в производстве. Поэтому мне интересно, есть ли способ заменить это, используя 'Mockito.when' – Richard

4

Обычной практикой (описано в книге Growing объектно-ориентированного программного обеспечения, руководствуясь испытаний) делегировать ResponsAbility создания экземпляра даты, чтобы соавтора.

Представьте, что вы есть класс, как это:

public class Clock { 
    public LocaleDate now(){ 
    return new LocalDate(); 
    } 
} 

, то ваш код может стать

public static int getAge(LocalDate birthdate, Clock clock) { 
    LocalDate today = clock.now(); 
    Period period = new Period(birthdate, today, PeriodType.yearMonthDay()); 
    return period.getYears(); 
} 

Я бы хорошо не испытывая Clock#now, как это тривиально правильно, но теперь я могу передать экземпляр mocked clock для тестирования метода getAge.

Теперь это означает, что класс, использующий статический getAge, должен обеспечивать часы, часы будут зависеть от этого класса. Такие зависимости можно вводить различными способами.

Я лично посещаю школу injection by constructor, но ничего не работает с injection by reflection на заводе-изготовителе (который может быть перегружен в анонимный подкласс, используемый для создания тестового экземпляра).

Эта проблема и дизайн я предлагаю подробно рассматриваются в the book, во многих blog posts и stack overflow (это выглядит как Java 8 имеет direct support для него, если вы готовы перейти к java.time)

1

Так , сначала позвольте мне сказать, что я согласен с Jean. Однако я обнаружил, что эта схема настолько распространена. Я реализовал многоразовое решение в библиотеке GitHub под названием LibEx. Он называется DateSupplier. Для получения текущего DateTime вы используете DateSupplier.getCurrentDateTime(). Затем в тестах вы используете @Rule DateController, который позволяет использовать datController.setCurrentDateTo...(). Когда это установлено в тесте, DateSupplier вернет значение, указанное в DateController.

Вот ссылки:

Ваш тест будет выглядеть следующим образом ..

public class DateControllerTest extends TestBase { 

@Rule 
public DateController dateContoller = new DateController(); 

@Test 
public void testSetCurrentTime() { 
    // setup 
    Date date = new Date(123443); 

    // test 
    dateContoller.setCurrentTime(date); 

    // verify 
    assertDateEquals(date); 
} 

private void assertDateEquals(Date date) { 
    assertThat(DateSupplier.getCurrentDate(), equalTo(date)); 
    assertThat(DateSupplier.getCurrentDateInMilliseconds(), equalTo(date.getTime())); 
} 

Поскольку DateController является Rule, он сбросит поведение по умолчанию после каждого теста. Кроме того, DateController находится в модуле libex-test, который должен быть областью тестирования, поэтому он находится в вашем рабочем коде.

-1

Значит, вы хотите, чтобы дата рождения кого-то повернулась на 46 сегодня? (Ваш вопрос не ясен.)

java.time

Создатели Joda-время говорят нам, чтобы перейти к использованию java.time рамки, встроенной в Java 8, а затем, как только это удобно.

ZonedDateTime birthdateOf46YearOld = ZonedDateTime.now().minusYears(46); 

Этот объект неявно назначен текущим часовым поясом JVM. Я рекомендую всегда быть явным с вашим часовым поясом.

ZoneId zoneId = ZoneId.of("America/Montreal"); // Or… ZoneOffset.UTC …or… ZoneId.systemDefault(). 
ZonedDateTime birthdateOf46YearOld = ZonedDateTime.now(zoneId).minusYears(46); 

Или вы хотите проверить, соответствует ли дата-время в руке такой же, как и дата рождения?

Boolean hit = someZdt.isEqual(birthdateOf46YearOld); 

Если вы заботитесь только о дате без времени в день или часового пояса, а затем использовать LocalDate, подобно Joda-времени. Обратите внимание, что часовой пояс имеет решающее значение для определения сегодняшней даты, поскольку он варьируется в разных часовых поясах по всему миру.

LocalDate birthdate = LocalDate.now(zoneId).minusYears(46) ; 

Если вы просто хотите истекшее время в годы между парой объектов LocalDate, используйте Period класс.

LocalDate today = LocalDate.now(zoneId); 
LocalDate birthDate = … ; 
Period period = Period.between(birthDate , today); 
Integer ageInYears = period.getYears(); 
Boolean hit = ageInYears.equals (Integer.valueOf(46)) ;  

Joda время

Если Java 8 или более поздняя версия не доступен для вас, такие же кода работает в Joda-Time.

DateTimeZone zone = DateTimeZone.forID("America/Montreal"); 
DateTime birthdate = DateTime.now(zone).minusYears(46); 
+0

Dear Down-Voter: Пожалуйста, оставите критику вместе с вашим голосованием. –

Смежные вопросы