2015-08-13 5 views
3

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

Итак, речь идет о добавлении большего количества слоев косвенности (интерфейсы, которые могут быть окурками/макетами в модульных тестах).

Но: где-то в моих тестах у меня должна быть «реальная» реализация моей зависимости. Так что насчет этого? Контрольная работа? Не тестировать?

Возьмем такой пример:

У меня были некоторые зависимости на пути, которые мне нужно в моем приложении. Поэтому я извлек интерфейс, IPathProvider (что я могу подделать в своих тестах). Вот реализация:

public interface IPathProvider 
{ 
    string AppInstallationFolder { get; } 
    string SystemCommonApplicationDataFolder { get; } 
} 

Конкретное PathProvider выглядит следующим образом:

public class PathProvider : IPathProvider 
{ 
    private string _appInstallationFolder; 
    private string _systemCommonApplicationDataFolder; 

    public string AppInstallationFolder 
    { 
     get 
     { 
      if (_appInstallationFolder == null) 
      { 
       try 
       { 
        _appInstallationFolder = 
         Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); 
       } 
       catch (Exception ex) 
       { 
        throw new MyException("Error reading Application-Installation-Path.", ex); 
       } 
      } 
      return _appInstallationFolder; 
     } 
    } 

    public string SystemCommonApplicationDataFolder 
    { 
     get 
     { 
      if (_systemCommonApplicationDataFolder == null) 
      { 
       try 
       { 
        _systemCommonApplicationDataFolder = 
         Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); 
       } 
       catch (Exception ex) 
       { 
        throw new MyException("Error reading System Common Application Data Path.", ex); 
       } 
      } 
      return _systemCommonApplicationDataFolder; 
     } 
    } 
} 

проверить ли вы такой код, и если, как?

+0

Вот несколько продуктов для размышлений об модульных тестах: http://www.rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf –

ответ

1

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

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

Как таковые, они подпадают под действие integration testing - не модульное тестирование.

Обычно я просто помечаю свои тесты (например, атрибутом xUnit Trait), чтобы они не отличались от обычных тестов, и поэтому я могу отключить их при автономной работе (например, без базы данных). Альтернативой было бы разделить их на совершенно новый проект в том же решении, но я лично считаю, что это слишком много.

[Fact, Trait("Category", "Integration")] 
public void ReturnsCorrectAppInstallationFolder() 
{ 
    // Arrange 
    var assemblyFilename = Path.GetFilename(typeof(SomeType).Assembly.Location); 
    var provider = new PathProvider(); 

    // Act 
    var location = provider.AppInstallationFolder; 

    // Assert 
    Assert.NotEmpty(Directory.GetFiles(location, assemblyFilename)) 
} 
+0

Я согласен с вашим заявлением, но это не так. действительно подходящий ответ на вопрос. Он не спрашивает, какой тип теста это будет ... –

+0

@JamieRees Я предполагаю, что в итоге я ответил на часть «Вы проверяете такой код», но не на «как». – dcastro

+0

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

0

Ответ зависит от вашего определения «единица». В случае, когда класс используется как единица, тогда ответ да. Однако тестирование отдельных классов имеет очень ограниченную ценность для бизнеса, если вы не разрабатываете какую-либо библиотеку классов.

Другая альтернатива - определить устройство как требование уровня пользователя (или системы). Тест для этого типа устройства будет осуществляться в соответствии с: данным пользователем X, проверкой на выход системы Y. Единицы, определенные таким образом, имеют определенную измеримую ценность для бизнеса, которая может быть отнесена к пользовательским требованиям.

Например, при использовании user stories вы можете иметь такие требования, как:

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

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

Дано: Пользователь указал C:\Program Files\MyApp как установить папку .

Когда: Установщик запустился.

Затем: на диске есть C:\Program Files\MyApp, и все файлы приложений присутствуют в этом месте.

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

0

Два ответа имеют большую ценность, но я добавлю еще одну вещь, которая, как я считаю, имеет большое значение.

У меня такое чувство, что люди часто завязываются в дискуссиях о том, что нужно тестировать, а что нет. Это что-то должно рассматриваться как единое целое или оно не должно. Это интеграция или нет.

Вообще, цель модульных тестов заключается в убедиться, что наш код работает как задумано. ИМО мы должны проверить все (независимо от того, что мы можем), которые могут сломаться. Организовать его в какой-то формальный тип теста и назвать его необходимо, но он имеет второстепенное значение для самого теста. Мой совет был бы в том, что если у вас есть какие-то сомнения, всегда задавайте себе вопрос: «Боюсь, что его можно сломать?». Итак ... «где остановиться»? Где вы не боитесь, что функция сломается.

И обратно к вашему конкретный случай. Как заметил @dcastro, это действительно много похоже на интеграционное тестирование, а не на классическое логическое тестирование. Независимо от того, как мы это называем, - может ли это быть нарушено? Да, оно может. Следует ли тестировать? МОЖЕТ быть протестирован, хотя я бы не назвал его решающим. Существует немного собственной добавленной логики, и сложность низкая. Я бы это испытал? Да, если бы у меня было время сделать это. Как мне это сделать? Пример кода @dcastro - это то, как я подхожу к проблеме.

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