2012-02-11 6 views
3

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

Рассмотрим следующий пример:

У меня есть класс Article, который имеет коллекцию цен. Он имеет метод GetCurrentPrice который определяет текущую цену, основанную на несколько правил:

public class Article 
{ 
    public string Id { get; set; } 
    public string Description { get; set; } 
    public List<Price> Prices { get; set; } 

    public Article() 
    { 
     Prices = new List<Price>(); 
    } 

    public Price GetCurrentPrice() 
    { 
     if (Prices == null) 
      return null; 

     return (
      from 
      price in Prices 

      where 

      price.Active && 
      DateTime.Now >= price.Start && 
      DateTime.Now <= price.End 

      select price) 
      .OrderByDescending(p => p.Type) 
      .FirstOrDefault(); 
    } 
} 

PriceType перечисления и Price класса:

public enum PriceType 
{ 
    Normal = 0, 
    Action = 1 
} 

public class Price 
{ 
    public string Id { get; set; } 
    public string Description { get; set; } 
    public decimal Amount { get; set; } 
    public PriceType Type { get; set; } 
    public DateTime Start { get; set; } 
    public DateTime End { get; set; } 
    public bool Active { get; set; } 
} 

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

Я имею в виду испытания устройства, такие как этот (псевдо):

[TestMethod()] 
public void GetCurrentPriceTest() 
{ 
    var articles = getTestArticles(); 
    foreach (var article in articles) 
    { 
     var price = article.GetCurrentPrice(); 
     // somehow compare the gotten price to a predefined value 
    } 
} 
  • Я читал, что «множественным утверждает зло», но мне не нужно их проверить все условия здесь? Или мне понадобится отдельный блок тест на состояние?

  • Как я могу получить модульный тест с набором тестовых данных? Должен ли я высмеивать репозиторий? И должны ли эти данные также включать ожидаемые значения ?

ответ

3

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

[TestMethod] 
public void Foo() 
{ 
    // arrange 
    var article = new Article(); 
    // TODO: go ahead and populate the Prices collection with dummy data 


    // act 
    var actual = article.GetCurrentPrice(); 

    // assert 
    // TODO: assert on the actual price returned by the method 
    // depending on what you put in the arrange phase you know 
} 

и так далее вы можете добавить другие модульные тесты, где бы вы только изменить arrange и assert фазы для каждого возможного входа.

+0

Что такое 'unit' в этом случае? Я просто хочу знать, работает ли функция GetCurrentPrice. Является ли каждый отдельный вход «единицей» и правильность метода зависит от всех этих модульных тестов? Или это сам метод? – diggingforfire

+0

@ diggingforfire, нет «единицы». Но это потому, что ваш код разработан таким образом, что нет «единицы». Класс 'Article' делает 2 вещи: у него есть свойства для хранения некоторых данных, и он содержит метод для управления этими данными. Таким образом, вы не можете тестировать эти 2 отдельно. Если вы хотели бы отделить эти обязанности, вы могли бы определить «GetCurrentPrice» в отдельном классе репозитория, который в качестве аргумента принимал бы экземпляр «Article». –

+0

Не может ли это привести к модели анемичного домена? Я бы предпочел, чтобы сама «статья» содержала эту логику. Кажется, что тестирование устройства немного сложнее, но .. – diggingforfire

2

Вам не нужно несколько утверждений. Вам нужно несколько тестов только с одним утверждением.

+0

Я бы не согласился здесь. Я думаю, вы можете комбинировать данные теста, пока ожидаете того же результата.Для меня нет оснований писать 100 единичных тестов, когда я могу достичь одного и того же результата в одном тесте в рамках итеративного шаблона. Это предполагает, что результаты испытаний для каждого должны быть одинаковыми. Примером здесь может служить словарь ключевых пар значений, которые использовались в качестве тестовых данных для каждого ключа, переданного в метод. Возвращаемое значение метода должно быть значением пары значений ключа. Я не вижу причин, почему это неэффективно. – tsells

+0

В конце дня - выполняется одна и та же оценка данных - и если это не сработает - я должен выяснить, почему так или иначе - запустите отладчик и исследуйте тест. Те же результаты - намного проще в обслуживании ..... – tsells

+0

@tsells: Я начинаю с создания единого теста, затем второго модульного теста, затем рефакторинга. Я вполне мог бы достигнуть уровня итеративного теста, хотя это имеет тот недостаток, что отказ одного теста приведет к тому, что остальные тесты не будут выполнены. –

2

новый тест для каждого условия запуска и одного утверждения, f.e.

[Test] 
public void GetCurrentPrice_PricesCollection1_ShouldReturnNormalPrice(){...} 

[Test] 
public void GetCurrentPrice_PricesCollection2_ShouldReturnActionPrice(){...} 

, а также тест на границах

для модульных тестов я диаграммы направленности

MethodName_UsedData_ExpectedResult() 
+0

Итак, у вас будет тест на каждый возможный ввод и соответствующий результат? Это звучит логично. Похоже, для этого потребуется много ручного кодирования. Есть ли способы легко обеспечить тесты такими данными? – diggingforfire

+0

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

+0

Resharper кричит на вас за этот образец модульного тестирования. Просто любопытно - зачем вам имя метода там? Вы не видите, какой метод вызывается внутри теста? – tsells

2

Я думаю, что вам нужно datadriven тестирование. В vsts есть атрибут, называемый Datasource, используя его, вы можете отправить тестовый метод нескольким тестовым случаям. Убедитесь, что вы не используете несколько утверждений. Вот одна ссылка MSDN http://msdn.microsoft.com/en-us/library/ms182527.aspx

Надеюсь, это вам поможет.

+0

Почему данные управляются? Это не проверка базы данных. – tsells

+0

Мы используем тестирование datadriven, когда нам нужно протестировать метод с несколькими входами. Это может быть любой метод. –

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