2011-01-05 3 views
7

Я пытаюсь модульным тестированием методы в классе, который инициализирует некоторые частные поля:Как проверить метод void, который изменяет только переменные частного класса?

public void init(Properties props) throws Exception { 

    this.language = props.getProperty(Constants.LANGUAGE,Constants.LANGUAGE_DEFAULT); 
    this.country = props.getProperty(Constants.COUNTRY,Constants.COUNTRY_DEFAULT); 

     try { 
      this.credits = Integer.valueOf(props.getProperty(Constants.CREDITS_OPTION_NAME, Constants.CREDITS_DEFAULT_VALUE)); 
     } catch (NumberFormatException e) { 
      throw new Exception("Invalid configuration: 'credits' does not contain a valid integer value.", e); 
     } 
     //rest of method removed for sake of simplicity 
    } 

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

  1. Сделать общедоступными методы доступа к закрытым полям, затем вызвать эти методы после тестирования метода init.
  2. Сделайте единичный тест только методом вызова init и предположим, что все работало корректно, не было исключено.

Как вы думаете, что является идеальным способом протестировать этот метод?

+0

Есть ли причина, по которой никто не предлагал добавить еще один тест, который вызывает сеттер, а затем вызывает «другой метод в том же классе, который требует установки этих полей?» Я довольно новичок в TDD и склонялся к такому решению в своей собственной работе, есть ли проблемы с этим? Является ли это еще модульным тестированием или чем-то еще, например, интеграционным тестированием или чем-то еще? как представляется, предлагается здесь: http://stackoverflow.com/questions/3193257/should-i-test-public-class-function-that-changes-only-internal-state-of-the-obje –

ответ

9

Вы можете использовать отражение, чтобы получить значения частных полей. Например:

Field field = YourClass.class.getDeclaredField("language"); 
field.setAccessible(true); //override the access restriction of it being private 
field.get(yourObject); 

Если весна на вашем пути к классам, вы можете использовать его ReflectionUtilsReflectionTestUtils /.

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

Если объект находится в недействительном состоянии, если поля не установлены, то сам объект должен нести ответственность за его действие, путем исключения исключения.

+0

Спасибо, в в конце я решил выбросить исключение из моего метода init, если значения были неправильными. –

1

Способствует ли ваш JUnit метод напрямую? Тогда ссылка на объект объекта будет одинаковой, вы должны иметь доступ к языку и стране, поскольку для кредитов выполняется пересчет в вашем JUnit.

Общественный доступ для частных методов также является хорошим выбором.

+0

Теперь это не будет проверять тестируемый класс. –

+0

Публичные методы доступа будут работать, но тогда я подвергаю значения поля вне класса, когда они не должны быть видимыми. Я все для рефакторинга кода, чтобы сделать его более проверяемым, но это не кажется «правильным» в этой ситуации. –

4

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

Если вы делаете строгий TDD, вы не должны даже добавить эти поля, пока вы не тест, который на самом деле имеет преимущество них :)

+0

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

+0

+1 для «вы даже не должны добавлять эти поля до тех пор, пока не получите тестовый пример». – Raedwald

9

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

Некоторая философия: почему вас волнует, правильно ли они установлены? Если ответ «так, что класс тогда ведет себя правильно», вы можете проверить, что они были установлены правильно, путем тестирования ожидаемого последующего поведения. Если, однако, их неправильное использование не имеет эффекта, они являются избыточными, и вы должны их удалить.

Другой плакат предложил использовать отражение для доступа к закрытым полям. Я советую против этого; все, что помечено как частное, должно быть детальностью реализации класса и поэтому не должно быть непосредственно протестировано. Вместо этого вы должны проверить опубликованный API своего класса. Тогда у вас есть свобода реорганизовать его легко, изменив детали (частные).

+0

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

+0

Если сообщение об ошибке не сообщается, поля не имеют эффекта, поэтому я бы рекомендовал удалить их. Или, скорее, отложить их добавление до тех пор, пока вы не будете работать над этим методом. – Raedwald

+0

При нормальных обстоятельствах сообщалось об ошибке, но в тестовой ситуации эти внешние зависимости нужно издеваться - следовательно, ошибка не будет выбрана из макета, но на самом деле требуются поля. Установка значений полей только в методе, в котором они используются, имеет смысл, но значения, из которых они установлены (реквизиты), доступны только для метода init. –

1

Лично я бы просто проверил общественные методы. Иногда вам нужно проверять внутренности, но это редко.

BTW: Альтернатива общедоступным геттерам - сделать модульное тестирование в том же пакете и предоставить локальные геттеры.

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