Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Design, Quality, Testing > Юнит тесты календаря


Автор: LSD 10.5.2012, 13:20
Есть класс который реализует некоторую логику по работе с календарем. Вся логика по работе с датами инкапсулирована в этом классе. Возник вопрос, как тестировать функциональность в разные моменты времени, т.е. грубо говоря надо подменить результат System.currentTimeMillis(). Можно конечно сделать в классе кастомный метод getTime() и в тестах подменять результат его работы, но выглядит как-то криво. Может есть более другие методы?

Автор: Старовъръ 10.5.2012, 13:36
Можно или использовать какие-то свои утилитные классы что-то вроде http://sonar.jtalks.org/resource/index/605, создавать в продакшн коде обычный, а в тестах подменять на http://sonar.jtalks.org/resource/index/661, а можно просто выносить статику в другой метод этого же класса, делать его package-private и создавать spy(), в котором подменять этот метод в SUT. 
Оба способа предусматривают, что скорей всего видимость какого-то члена класса будет минимум package-private и он будет открыт скорей всего только для тестов, но это небольшой trade-off за тестируемость. К тому же такой член класса можно пометить как @VisibleForTesting (взять из guava или написать свою документирующую аннотацию).

Автор: Stolzen 10.5.2012, 13:52
Первое, что приходит в голову - вынести получение времени в отдельную зависимость и мокать ее (как и написал Старовъръ)
А второе - это использовать PowerMock, он статику позволяет мокать. Как именно он это делает, я не знаю, ни разу не пользовался, обычно первым способом обхожусь.

Автор: LSD 10.5.2012, 14:29
Цитата(Старовъръ @  10.5.2012,  14:36 Найти цитируемый пост)
Можно или использовать какие-то свои утилитные классы что-то вроде такого, создавать в продакшн коде обычный, а в тестах подменять на моковый

Вот именно этого и хотелось бы избежать уж больно код уж больно enterprise style получается smile


Цитата(Stolzen @  10.5.2012,  14:52 Найти цитируемый пост)
А второе - это использовать PowerMock, он статику позволяет мокать.

Это как раз http://code.google.com/p/powermock/wiki/MockSystem.

Автор: Старовъръ 11.5.2012, 16:56
PowerMock в нелегаси системах, наверно, не лучший выбор. Если интересно все-таки легковесное решение, то лучше все-таки выделить отдельный метод в классе типа getTime() и сделать Mockito.spy(sut) и дальше замокать его.

Автор: LSD 11.5.2012, 16:58
Цитата(Старовъръ @  11.5.2012,  17:56 Найти цитируемый пост)
PowerMock в нелегаси системах, наверно, не лучший выбор.

Почему?

Автор: Старовъръ 13.5.2012, 14:26
  • Тяжеловесный инструмент для такой мелочи, его основная ниша - legacy code. 
  • Придется описывать всякие @RunWith(PowerMock..), что не позволит использовать другие раннеры в JUnit.
  • Он не так тривиален, бывают косяки, которых совсем не ожидаешь - например, он использует свой собственный ClassLoader, у нас не так давно была проблема из-за этого (уже не помню конкретные случаи, коллега тест писал, не я), еще проблемы были что каким-то магическим образом он не очищал состояние мока между тестами (тоже не конкретно я сталкивался, к сожалению).

Автор: Stolzen 22.6.2012, 23:19
Вот и наткнулся самолично на описанные грабли - при использовании PowerMock JaCoCo/EclEmma не могут получать данные о тестовом покрытии из-за вмешательств первого в байт-код классов. Проблему решил запуском этих тестов через Cobertura, но осадочек остался.

Автор: LSD 12.7.2012, 10:56
У нас PowerMock прекрасно работает, и не пришлось извращаться с time provider.

Автор: powerOn 28.8.2012, 19:29
а я бы лучше выбрал тайм провайдер. Использовать power mock значит создавать прецедент, по которму он сможет применяться для аналогичных случаев (мокать не мокируемое), где на самом деле нужен рефакторинг. Да и в литературе советуют создавать "анти-коррупционный" слой, если API платформы уныл - а такое не редкость. Вот тут: http://www.growing-object-oriented-software.com/ пример с датами как раз разбирают в одной из глав.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)