2009-07-29 3 views
15

Как легко выкачать статический метод в Java?Как я могу легко измотать статический метод в Java (jUnit4)

Я использую Spring 2.5 и JUnit 4.4

@Service 
public class SomeServiceImpl implements SomeService { 

    public Object doSomething() { 
     Logger.getLogger(this.class); //a static method invoked. 
     // ... 
    } 
} 

Я не контролирую статический метод, который моя служба должна вызывать поэтому я не рефакторинг, чтобы быть более блок-проверяемым. Я использовал пример Log4J Logger, но реальный статический метод аналогичен. Невозможно изменить статический метод.

Ведение Grails работы, я привык использовать что-то вроде:

def mockedControl = mockFor(Logger) 
mockControl.demand.static.getLogger{Class clazz-> … } 
… 
mockControl.verify() 

Как сделать что-то подобное в Java?

+0

Можете ли вы изменить реализацию SomeServiceImpl? –

+0

Ничего, Джон Скит только что опубликовал то, что думал. Я горжусь! (думая, как Джон Скит хе-хе) –

+0

Да, я могу изменить SomeServiceImpl, но зачем мне это нужно? Почему дополнительная косвенность? –

ответ

0

В принципе, это не простой способ сделать это в Java + Spring 2.5 & JUnit 4.4 на данный момент.

Хотя рефакторинг и реферат можно отвлечь от статического вызова, рефакторинг кода не является тем решением, которое я искал.

JMockit выглядел так, как будто это сработает, но несовместимо с Spring 2.5 и JUnit 4.4.

+2

Предлагается PowerMock, способный имитировать статические методы, поэтому есть простой способ: – Richard

+0

PowerMock имеет серьезные утечки памяти, что мы обнаружили после просмотра использования памяти и продолжительности сборки Jenkins, когда мы использовали плагин maven, который автоматически выполнил бы модульные тесты для обеспечения качества сборки. Вот почему PowerMock - плохой вариант. – Igor

+0

Проверьте это, https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/ Вы можете @RunWith (PowerMockRunner.class), а затем делегировать @PowerMockRunnerDelegate (SpringJUnit4ClassRunner .класс). Конечно, это потребует от вас работы с некоторыми последними версиями. – Yasin

14

Вы хотите сказать, что не можете управлять кодом? Потому что если вы управляете вызовами до статическим методом, но не самой реализацией, вы можете легко сделать это проверяемым. Создайте интерфейс зависимостей с помощью одного метода с той же сигнатурой, что и статический метод. Ваша производственная реализация просто вызовет статический метод, но все, что в настоящее время вызывает статический метод, вызовет через интерфейс.

Вы можете затем вытереть этот интерфейс обычным способом.

1
public interface LoggerWrapper { 
    public Logger getLogger(Class<?> c); 
    } 
public class RealLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return Logger.getLogger(c);} 
    } 
public class MockLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return somethingElse;} 
    } 
0

Это одна из причин, по которой статические методы являются плохими.

Мы перестроили большинство наших заводов, чтобы иметь сеттеры, чтобы мы могли установить в них макет объектов. Фактически, мы придумали что-то близкое к инъекции зависимостей, когда один метод действовал как фабрика для всех наших синглетов.

В вашем случае может быть использован метод Logger.setLogger() (и сохранение этого значения). Если вам нужно, вы можете расширить класс регистратора и затенять метод getLogger своим собственным.

4

Структура JMockit обещает позволить насмехаться над статическими методами.

https://jmockit.dev.java.net/

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

Независимо от того, оправданы или нет такие претензии, структура JMockit сама по себе довольно интересна, хотя мне еще предстоит ее попробовать.

+1

Использование статических методов всегда будет спорным. Но может ли кто-нибудь действительно возражать против разумного использования ключевого слова final? Рассмотрим, например, то, что книга «Эффективная Ява» должна сказать об этом (пункт 17). –

+1

Когда я посмотрел в «Использование JMockit», я обнаружил, что Spring 2.5.x несовместим с JUnit 4.5+ и что JMockit совместим с JUnit 4.4 (и ниже), см. Http://jira.springframework.org/browse/SPR-5145 через http://stackoverflow.com/questions/693115/junit4-spring-2-5-asserts-throw-noclassdeffounderror –

+0

Так что JMockit на данный момент не может быть и речи. –

0

Вы можете использовать AspectJ, чтобы перехватить вызов статического метода и сделать что-то полезное для вашего теста.

+1

Как мне это сделать? Есть простой пример? –

1

Как еще один ответ, указанный выше, JMockit может издеваться над статическими методами (и что-то еще).

У него даже есть прямая поддержка фреймворков регистрации. Например, вы могли бы написать:


@UsingMocksAndStubs(Log4jMocks.class) 
public class SomeServiceTest 
{ 
    // All test methods in this class will have any calls 
    // to the Log4J API automatically stubbed out. 
} 

Поддержка JUnit 4.4 была снижена, однако. Поддерживаются JUnit 3.8, JUnit 4.5+ и TestNG 5.8+.

4

PowerMock имеет такую ​​способность. Он также может макетировать экземпляры объектов внутри класс под тестированием. Если ваш протестированный метод вызывает новый Foo(), вы можете создать макет объекта для этого Foo и заменить его в методе, который вы тестируете.

Возможны также блокирующие конструкторы и статические инициализаторы. Все эти вещи считаются непроверяемым кодом и поэтому не рекомендуется делать, но если у вас есть устаревший код, его изменение не всегда является опцией. Если вы находитесь в этом положении, PowerMock может вам помочь.

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