Какова стратегия модульного тестирования для переадресации вызовов методов? - PullRequest
2 голосов
/ 19 сентября 2008

У меня есть следующий сценарий:

public class CarManager
{
  ..

  public long AddCar(Car car)
  {
      try
      {
         string username = _authorizationManager.GetUsername();
         ...
         long id = _carAccessor.AddCar(username, car.Id, car.Name, ....);
         if(id == 0)
         {
             throw new Exception("Car was not added");
         }
         return id;
      } catch (Exception ex) {
         throw new AddCarException(ex);
      }
  }

  public List AddCars(List cars)
  {
     List ids = new List();
     foreach(Car car in cars)
     {
         ids.Add(AddCar(car));
     }
     return ids;
  }
}

Я высмеиваю _reportAccessor, _authorizationManager и т. Д.

Теперь я хочу провести тестирование класса CarManager. Должен ли я иметь несколько тестов для AddCar (), таких как

AddCarTest()
AddCarTestAuthorizationManagerException()
AddCarTestCarAccessorNoId()
AddCarTestCarAccessorException()

Для AddCars () я должен повторить все предыдущие тесты, так как AddCars () вызывает AddCar () - это похоже на повторение? Должен ли я, возможно, не вызывать AddCar () из AddCars ()?

Пожалуйста, помогите.

Ответы [ 5 ]

2 голосов
/ 19 сентября 2008

Здесь есть два вопроса:

  • Юнит-тесты должны выполнять больше, чем методы тестирования по одному. Они должны быть разработаны, чтобы доказать, что ваш класс может выполнять работу, для которой он предназначен, при интеграции с остальной частью системы. Поэтому вы должны смоделировать зависимости, а затем написать тест для каждого способа, которым ваш класс будет фактически использоваться. Для каждого (нетривиального) класса, который вы пишете, будут сценарии, в которых клиентский код вызывает методы в определенном шаблоне.
  • Нет ничего плохого в том, что AddCars вызывает AddCar. Вы должны повторять тесты для обработки ошибок, но только тогда, когда это служит цели. Одним из неофициальных правил юнит-тестирования является «тест до скуки» или (как мне нравится думать об этом) «тест до исчезновения страха». В противном случае вы будете писать тесты навсегда. Поэтому, если вы уверены, что тест не принесет никакой пользы, не пишите его. Конечно, вы можете ошибаться, и в этом случае вы можете вернуться позже и добавить его. Вам не нужно производить идеальный тест с первого раза, просто твердую основу, на которой вы можете построить, чтобы лучше понять, какой у вас класс нужно сделать.
1 голос
/ 29 января 2009

Должен ли я пройти несколько тестов для AddCar (), например

AddCarTest () AddCarTestAuthorizationManagerException () AddCarTestCarAccessorNoId () AddCarTestCarAccessorException ()

Абсолютно! Это говорит вам ценную информацию

Для AddCars () я должен повторить все предыдущие тесты, так как AddCars () вызывает AddCar () - похоже как повторяться? Должен ли я, возможно, не вызывать AddCar () из AddCars ()?

Вызов AddCar из AddCars - отличная идея, он позволяет избежать нарушения принципа СУХОЙ. Точно так же вы должны повторять тесты. Подумайте об этом так - вы уже написали тесты для AddCar , поэтому при тестировании AddCards вы можете предположить, что AddCar делает то, что говорит на жестяной банке .

Скажем так: представьте, что AddCar был из другого класса. Вы бы не знали администратора авторизации. Протестируйте AddCars без знания о том, что должен делать AddCar.

Для AddCars вам нужно протестировать все нормальные граничные условия (работает ли пустой список и т. Д.) Вам, вероятно, не нужно тестировать ситуацию, когда AddCar выдает исключение, поскольку вы не пытаетесь его перехватить. AddCars.

1 голос
/ 19 сентября 2008

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

В такой ситуации, как AddCars() вызов AddCar() Я бы высмеял метод AddCar() и посчитал, сколько раз он вызывается AddCars(). Библиотека макетов, которую я использую, позволяет мне создавать макет CarManager и использовать только метод AddCar(), но не AddCars(). Затем ваш модульный тест может установить, сколько раз он будет ожидать вызова AddCar(), что вы знаете по размеру списка автомобилей, переданных в.

1 голос
/ 19 сентября 2008

При юнит-тестировании класса AddCar создайте тесты, которые будут проверять каждый путь кода. Если _authorizationManager.GetUsername () может выдать исключение, создайте тест, в котором будет использоваться ваш макет для этого объекта. Кстати: не бросайте и не ловите экземпляры Exception, но извлекайте значимый класс Exception.

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

Иногда вам придется изменить дизайн класса для тестируемости.

1 голос
/ 19 сентября 2008

Модульный тест должен фокусироваться только на соответствующем тестируемом классе. Все атрибуты класса, которые не относятся к одному и тому же типу, должны быть проверены.

Предположим, у вас есть класс (CarRegistry), который использует какой-то объект доступа к данным (например, CarPlatesDAO), который загружает / сохраняет номера автомобилей из реляционной базы данных.

Когда вы тестируете CarRegistry, вас не должно волновать, правильно ли работает CarPlateDAO; Так как у нашего DAO есть свой собственный модульный тест.

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

Mocking позволяет разделить тестируемые классы и лучше сосредоточиться на конкретной функциональности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...