дешевый способ макетировать интерфейс без лишних затрат времени выполнения - PullRequest
1 голос
/ 22 июня 2010

Предположим, у меня есть интерфейс с множеством методов, которые я хочу смоделировать для теста, и предположим, что мне не нужно ничего делать, мне просто нужен тестируемый объект, чтобы иметь экземпляр этого. Например, я хочу провести некоторое тестирование / тестирование производительности для определенного фрагмента кода и не хочу, чтобы методы этого интерфейса вносили свой вклад.

Существует множество инструментов, позволяющих сделать это легко, например,

Interface mock = Mockito.mock(Interface.class);
ObjectUnderTest obj = ...
obj.setItem(mock);

или что угодно.

Однако все они идут с некоторыми накладными расходами во время выполнения, которых я бы предпочел избежать:

  • Mockito записывает все вызовы, сохраняя аргументы для проверки позже
  • JMock и другие (я полагаю) требуют, чтобы вы определили, что они собираются делать (не такая уж большая проблема), и затем выполнение проходит через прокси различных типов для фактического вызова метода.
  • Старый добрый java.lang.reflect.Proxy и его друзья проходят, по крайней мере, еще несколько вызовов методов в стеке, прежде чем добираться до вызываемого метода, часто рефлексивно.

(Я желаю, чтобы меня исправили на любом из деталей этих примеров, но я верю, что принцип верен.)

То, к чему я стремлюсь, - это «настоящая» неоперируемая реализация интерфейса, такая, которую я мог бы написать вручную, когда все возвращает null, false или 0. Но это не помогает, если я чувствую себя ленивым, и интерфейс имеет множество методов. Итак, как я могу сгенерировать и создать такую ​​реализацию произвольного интерфейса без возможности выполнения во время выполнения?

Доступны такие инструменты, как Powermock, CGLib, которые используют генерацию байт-кода, но только как часть более широкого контекста насмешек / прокси, и я пока не выяснил, что выбрать из внутренних компонентов.

Хорошо, так что пример может быть немного надуманным, и я сомневаюсь, что прокси будет иметь слишком существенное влияние на время, но мне любопытно, как создать такой класс. Легко ли в CGLib, ASM?


РЕДАКТИРОВАТЬ: Да, это преждевременная оптимизация, и нет никакой необходимости делать это. После того, как я написал этот вопрос, я думаю, что последнее предложение не совсем убедило меня в том, что меня больше интересует, как это сделать в принципе, и простых способов динамической генерации классов, чем фактического варианта использования, который я дал. Возможно, плохо сформулировано с самого начала.

Ответы [ 2 ]

3 голосов
/ 22 июня 2010

Не уверен, что это то, что вам нужно, но мастер «нового класса» в Eclipse позволяет вам создать новый класс и указать суперкласс и / или интерфейс (ы).Если вы позволите, он будет автоматически кодировать фиктивные реализации всех интерфейсных / абстрактных методов (возвращая null, если void).Это довольно безболезненно.

Я подозреваю, что другие "знаменитые" IDE, такие как NetBeans и Idea, имеют аналогичные возможности.


РЕДАКТИРОВАТЬ:

Lookingна ваш вопрос еще раз, я удивляюсь, почему вы будете беспокоиться о производительности авто прокси при работе с тестовыми классами.Мне кажется, что если производительность - это проблема, вам следует тестировать «реальную» функциональность, а если вы все равно имеете дело с классами, в основном не реализованными, то вам не следует находиться в ситуации тестирования, где производительность имеет значение.

0 голосов
/ 14 февраля 2012

Для создания утилиты потребовалась бы небольшая работа, но, вероятно, не слишком сложная для базового ванильного интерфейса Java без «крайних случаев» (аннотации и т. Д.), Чтобы использовать генерацию кода Javassist для текстового создания класса во время выполнения, реализующего нульверсии каждого метода, определенного в интерфейсе.Это будет отличаться от прокси-объектов Javassist ProxyFactory (или CGLib Enhancer), которые все равно будут иметь несколько уровней косвенности.Я думаю в результирующем классе не было бы издержек из режима прямой генерации байт-кода.Если вы смелы, вы также можете погрузиться в ASM, чтобы сделать то же самое.

...