2015-04-28 5 views
1

Я прочитал этот вопрос: How do I test a class that has private methods, fields or inner classes? и кажется, что у меня может быть запах кода, но мой код очень прост для рефакторинга. что не так в дизайне, который я создал. Я создал класс делегата для обработки некоторых действий он три метода execute(Action);PopulateActionHandlers() и executeActionhandlers(); Моего класса, как показано ниже:Junit тест для частного метода

public class DelegateHandler{ 
    Map<Integer,ActionHandlers> handlerMaps; 

    public execute(Action action){ 
     populateActionHandlers(action); 
     executeActionHandlers(); 

    }//end of execute 

    //This method can create and populate more than one handlers in handlerMap 
    private populateActionHandlers(action){ 
     handlerMap = new LinkedHashMap<ActionHandlers>(); 
     if (action.isMultimode()){ 
      handlerMap.add(1,new handler(action.getabc())); 
      handlerMap.add(2,new handler(action.getabc()-1)); 
     }else{ 
      handlerMap.add(1,new handler(action)); 
     } 

    }//end of populateActionHandlers 

    //This method can execute more than one handlers in handlerMap 
    private executeActionHandlers(){ 
     for(ActionHandler actionHandler : handlerMap.values){ 
      actionHandler.executeAction(); 
     } 

    }//end of executeActionHandlers 
} 

Теперь я хочу проверить populateActionHandlers() метод с JUnit, который я сделал как частный, есть нет необходимости выставлять его вне этого класса. Если я проведу метод execute(), он проверит оба метода: populateActionHandlers() и executeActionHandlers(), которые одновременно тестируют два устройства, я хочу их протестировать отдельно. Дизайн (я думаю) кажется мне в порядке и не позволяет никаких проблем, но тогда я либо изменил бы доступ к методу (и только ради тестирования это не оправдывает это, на мой взгляд, правильно?) Или использовать рефлексия (это хорошая идея, она как-то не так-то чувствует, обычно ли люди используют рефлексию для тестирования юнита?). Так что единственное, что нельзя исключить, - это запах кода. Но может быть, мой код синус не помогает мне. Поэтому я хотел бы понять, могу ли я улучшить этот код.

+4

Я не думаю, что тестирование общественного метода проверяет две вещи. Есть только одна общественная операция. Класс предоставляет только одну публичную «вещь». Вы бы это испытали. Теперь у вас может быть несколько тестов, которые ссылаются на одну вещь в нескольких разных предварительных условиях, чтобы проверить отдельные пути кода в ней. Но тестирование публичной операции (классов) класса должно по дизайну также проверять все свои частные операции. – David

+0

Ваш код не будет компилироваться :) Как вы можете видеть свою частную функцию populateActionHandlers() вызывается открытым методом execute(). Таким образом, вы либо проверяете его во время тестирования execute(), либо если вам действительно нужно его протестировать, то вы можете: a) Используйте отражение, которое является моим любимым, но осуждаемое некоторыми . Б) используйте насмешливо, как powermock, для изменения executeActionHandlers логический и все еще выполнить тест() https://code.google.com/p/powermock/wiki/MockPrivate – Praeterii

+0

@Praeterii Код был примером. Я думаю, вы можете вызвать частную функцию из общедоступного метода. Учитывая код, я не могу проверить частный метод напрямую и должен использовать то, что вы предложили, что некоторые блоги говорят о запахе кода. Есть ли какие-то проблемы с моим дизайном? – sarmahdi

ответ

0

Рекомендация не тестировать частные методы не должна препятствовать тому, чтобы вы делали странный дизайн, оставив закрытый метод, но должны применять для проверки только методы, которые имеют четкую семантику.

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

Я хотел бы переписать программка в следующим образом:

... 
public execute(Action action){ 
    Map<Integer,ActionHandlers> handlerMap = populateActionHandlers(action); 
    executeActionHandlers(handlerMap); 
} 
... 

Сохранение результатов одной функции в частном поле только для извлечения его из этого поля в другой функции не THREADSAFE и труднее поддерживать.

Однако этот рефакторинг завершит работу над всеми (пока не написанными) тестами, которые проверили частный метод вашего примера, поскольку интерфейс изменен. Если вы только протестировали открытый метод, все тесты будут действительны после этого рефакторинга.

Я знаю несколько случаев, когда тестирование частных методов в порядке. Хотя тестирование частных методов часто можно избежать, я считаю, что проверка частного состояния иногда является лучшей альтернативой, чем проверка состояния публичных объектов. Такие проверки могут быть не такими надежными (причины, как указано выше), но общественное государство часто является неполным и трудно утверждать. В обоих случаях я использую фреймворк picklock, который позволяет получить доступ к приватным методам и полям удобным способом.

+0

Спасибо за ответ. Но все еще не решает проблему, мне нужно проверить, правильно ли заполняется Map обработчика populateHandlerMap() до вызова executeActionHandclers(). – sarmahdi

+0

Тот факт, что карта заполнена, является деталью реализации. Вы не должны проверять, что карта заполнена, но что правильные обработчики вызываются на этапе выполнения. Если это так, то карта должна быть заполнена. Если побочный эффект заполнения карты является частью спецификации общедоступного метода, тогда напишите геттер для карты и запросите его содержимое после его вызова. Я бы привел пример (также как вызвать частный метод), но для этого требуется тестовый объект, который компилируется (Action * может быть интерфейсом). – CoronA

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