2014-09-30 2 views
2

У меня есть простой метод, который вычисляет общее количество из коллекции.Отделение покрытия с foreach?

public void MethodToTest(Collection<int> collection) 
{ 
    int sum = 0; 
    foreach (int value in collection) 
    { 
     sum += value; 
    } 
} 

Цель состоит в том, чтобы получить 100% -ный охват филиала, используя инструмент opencoverage, запущенный в командной строке. Я также получил тест блока, который называют метод MethodToTest:

[TestMethod] 
public void TestMethodToTest() 
{ 
    BomProviderMock mock = new BomProviderMock(); 
    BomManager bomManager = new BomManager(mock); 

    List<int> list = new List<int>(); 
    for (int i = 0; i <= Int16.MaxValue; i++) 
    { 
     list.Add(i); 
    } 
    // Firts attempt with a non empty collection 
    bomManager.MethodToTest(new Collection<int>(list)); 

    // Second attempt with an empty collection 
    bomManager.MethodToTest(new Collection<int>()); 
} 

После использовали opencover инструмент, метод MethodToTest получил на 80% при охвате отрасли. Мой вопрос заключается в том, влияет ли цикл foreach на охват филиалов, если да, как я могу получить 100% с помощью этого простого кода?

+0

вместо написания foreach вы не могли бы использовать метод расширения коллекции 'foreach' и создать делегат? [Список .foreach] (http://msdn.microsoft.com/en-us/library/bwabdf9z (v = vs.110) .aspx) – MethodMan

+0

Я запускаю образец кода с другим инструментом покрытия кода (DotCover) и я получил 100% -ный охват кода. Может быть, что 'sum + = value;' не включается, потому что код оптимизирован и не учитывается вашим инструментом покрытия? Добавление оператора 'Debug.WriteLine (sum);' могло бы помочь в этом случае. – Sjips

+0

OpenCover смотрит на IL, созданный с помощью компиляции кода, и иногда компилятор добавляет больше инструкций IL, чем вы можете сопоставить свой код, поэтому это затрудняет получение покрытия на 100% с OpenCover. Иногда команда будет искать оптимизацию, но не часто (я добавлю это в список кандидатов). –

ответ

2

Я немного обновил ваш вопрос, используя некоторые linq вместо петель foreach. Требуется случайный номер (тот же самый список размеров, хотя), поэтому компилятор не будет «взбивать его» и должен его вычислить.

Я бы предложил сделать что-то с суммой в методе или вернуть его, это может изменить ваши результаты.

Последнее, но не менее важное: не одержим около 100%. Это никогда не произойдет в реальном проекте большой жизни. Просто убедитесь, что вы проверяете то, что может тормозить, и создайте свое программное обеспечение с учетом тестирования, так что это будет легко сделать.

void Main() 
{ 
    Random r = new Random(); 
    List<int> list = Enumerable.Range(1,Int16.MaxValue) 
           .Select (e => r.Next(0,Int16.MaxValue)) 
           .ToList(); 

    // Firts attempt with a non empty collection 
    MethodToTest(new Collection<int>(list)); 

    // Second attempt with an empty collection 
    MethodToTest(new Collection<int>()); 
} 

// Define other methods and classes here 
public void MethodToTest(Collection<int> collection) 
{ 
    var sum = collection.Sum (i => i); 
    // do something with it. If you're just voiding it and it doesn't get 
    // used, it might be removed by compiler. 
} 
+0

Я согласен - Дать тесты, чтобы получить покрытие, - это неправильно идти о тестировании, и 100% -ное покрытие филиалов обычно невозможно в реальной жизни (также вы сойдете с ума, если будете одержимы этим). Посмотрите на правильные тесты и/или используя методы TDD и следуя принципам SOLID, сначала он выглядит тяжело, но приносит пользу в долгосрочной перспективе. –

+0

у вас должно было быть + 1'е это, чтобы показать свою оценку :) (сказал, что всегда приятно видеть круглые номера на вашей статистике ... например ... 100%) – Noctis

+0

done ...... .. :) –

4

В [первоначальному] принят ответ указал ваш фактический сценарий сводится к collection.Sum() однако вы не сможете уйти с этим каждый раз.

Если мы используем TDD для разработки этого (избыточно я согласен, но легко объяснить) мы бы [возможно] сделать следующее (я также использую NUnit в данном примере из предпочтения)

[Test] 
public void Sum_Is_Zero_When_No_Entries() 
{ 
    var bomManager = new BomManager(); 
    Assert.AreEqual(0, bomManager.MethodToTest(new Collection<int>())); 
} 

, а затем напишите следующий код (примечание: мы пишем минимум для соответствия текущему набору тестов)

public int MethodToTest(Collection<int> collection) 
{ 
    var sum = 0; 
    return sum; 
} 

Мы тогда напишем новый тест, например,

[Test] 
[TestCase(new[] { 0 }, 0)] 
public void Sum_Is_Calculated_Correctly_When_Entries_Supplied(int[] data, int expected) 
{ 
    var bomManager = new BomManager(); 
    Assert.AreEqual(expected, bomManager.MethodToTest(new Collection<int>(data))); 
} 

Если мы провели наши тесты они все проходят (зеленый), поэтому нам нужно новое испытание (случаи)

[TestCase(new[] { 1 }, 1)] 
[TestCase(new[] { 1, 2, 3 }, 6)] 

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

public int MethodToTest(Collection<int> collection) 
{ 
    var sum = 0; 
    foreach (var value in collection) 
    { 
     sum += value; 
    } 
    return sum; 
} 

Теперь все мои тесты работают, и если я бегу, что через opencover я получаю 100% последовательность и охват ветви - ура .... И я сделал это без покрытия, как мой контроль, но писать правильные тесты для поддержите мой код.

НО есть «возможный» дефект ... что, если я перехожу в null? Время для нового теста для исследования

[Test] 
public void Sum_Is_Zero_When_Null_Collection() 
{ 
    var bomManager = new BomManager(); 
    Assert.AreEqual(0, bomManager.MethodToTest(null)); 
} 

Тест не проходит, поэтому нам необходимо обновить наш код, например.

public int MethodToTest(Collection<int> collection) 
{ 
    var sum = 0; 
    if (collection != null) 
    { 
     foreach (var value in collection) 
     { 
      sum += value; 
     } 
    } 
    return sum; 
} 

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

Теперь у нас есть хороший набор тестов, поэтому мы теперь можем безопасно реорганизовать наш код, например.

public int MethodToTest(IEnumerable<int> collection) 
{ 
    return (collection ?? new int[0]).Sum(); 
} 

И я сделал это, не затрагивая ни одного из существующих тестов.

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

+0

+1 для TTD и хороший пример. разве вам не нужны ваши тесты для возврата в NUnit, если вы используете «TestCase»? – Noctis

+0

Хм ... вот статья, которую я написал в [Unit testing] (http://www.codeproject.com/Articles/784791/Introduction-to-Unit-Testing-with-MS-tests-NUnit-a). Если у вас есть метод 'void' с заголовком' TestCase (...) ', я получаю:' Test ignored: Test method имеет тип возврата void, но ожидается результат (с использованием nunit) – Noctis

+0

@Noctis вы, возможно, используете Resharper? если так вам нужно обновить, поскольку это старая проблема http://stackoverflow.com/questions/9241232/does-nunit-testcase-attribute-with-result-property-work-incorrect –

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