Соответствующие методы уровня доступа при разделении больших методов на более мелкие? - PullRequest
2 голосов
/ 20 июля 2011

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

Что я сейчас делаю:

 public class WashingMachine {
      public Load wash(Load load) {
           // Removes one sock from load
           for (ClothingItem item : load.getItems()) {
                if (item.getType().equalsIgnoreCase("sock") {
                     load.removeItem(item);
                     .. // logic for sending sock to proper dimension
                     break;
                }
           }
           // rest of logic for cleaning clothes
      }
 }

Превращается в:

 public class WashingMachine {
      // Wash a load of laundry
      public Load wash(Load load) {
           // Removes one sock from load
           removeSock(load.getItems());
           // rest of logic for cleaning clothes
           ..
      }

      // Oh no, I can't unit test this easily!
      private void removeSock(List<ClothingItem> items) {
           ...
      }
 }

Ответы [ 2 ]

5 голосов
/ 20 июля 2011

Думайте о ваших общедоступных методах как о функциональности, которую вы хотите разрешить кому-либо использовать.

Некоторые из этих функций могут быть сложными, и вы правы, эта функциональность должна быть разделена на разные методы.Вопрос в том, «Какой у них доступ?»

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

Например, взять аналогию с автомобилем.Скажи, что твой метод accelerate().Это, вероятно, позвонит releaseGas().Однако вы не хотите, чтобы кто-то извне выпускал газ.Его следует вызывать только в контролируемой среде.

Тогда есть защищенный доступ.Защищенный доступ предназначен для методов, которые могут быть переопределены путем расширения классов.Это должны быть методы, выполняющие определенную часть работы, связанной с внутренней функциональностью.Снова беря пример с автомобиля, может быть RaceCar clas, который использует особый тип газа, и поэтому он хочет предложить свой собственный метод выпуска газа.Это может послужить причиной защиты releaseGas.

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

Конечно, иногда эти внутренние методы достаточно сложны, чтобы гарантировать свои собственные модульные тесты.Однако вам не нужно делать их защищенными.В этом случае вы можете сделать их доступ по умолчанию.(Ни публично, ни защищено).Пока ваш юнит-тест находится в одном пакете, вы сможете вызывать его.

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

Редактировать:

Комментарий Райана ниже мертв.Если ваш класс становится достаточно сложным, что требует тестирования его внутренних методов, его, вероятно, следует выделить в свой собственный класс, который затем можно будет независимо тестировать модулем.

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

1 голос
/ 20 июля 2011

Я думаю, вы должны разработать свой класс на основе (основного, а не тестового) кода, который будет его вызывать.Если ни у кого нет необходимости звонить WashingMachine.removeSock(), тогда я бы оставил это private.

Что касается модульного теста, то, конечно, это означает, что вы не можете проверить этот отдельный фрагмент логики в пределах WashingMachine - но вы все еще можете протестировать метод wash(), который, если это все, что видны другим компонентам, использующим WashingMachine, - это все, что вам действительно нужно для тестирования.

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

...