AVK Selected

Показавшиеся интересными, на мой вкус, посты

Re: как правильнее тест сделать

SergeyT. SergeyT.
Здравствуйте, Аноним, Вы писали:


А>Nunit

А>Есть вот такой метод для теста
А>Как лучше, оставить как есть или сделать через параметры и указывать все значения init1, do1, 0, 1 — через аттрибуты
А>Насколько это удобно будет отлаживать во 2м случае ?

Конечно здесь явно напрашиваются параметризованные тесты, ведь по сути, здесь не один тест, а два.

[TestCase("init1", "do1", Result = 0)]
[TestCase("init2", "do2", Result = 1)]
public int Test_That_Do_Produces_Expected_Result(string initData, string doData)
{
  // У нас же тут ООП, как никак, а раз так, то инварианты класса А
  // должны устанавливаться в конструкторе
  var a = new A(initData);

  return a.Do(doData);
}


Основной плюс параметризованных тестов в том, что это четко показывает, что у нас не один тест, а два. Ведь существуют правила написания юнит-тестов, один из вариантов которых называется F.I.R.S.T.. Одним из самых важных принципов является I — isolated, это значит, что если один из тестов падает, то другие должны продолжаться исполняться с чистого листа.

В исходном примере, если тест упадет при init1, то второй тест вообще не будет выполнен. Тем более, предложенный вариант очень плохо расширяем. А что если нам понадобиться покрыть десяток кейсов? Так и будем плодить константы и плодить один и тот же код внутри теста? Как-то это кажется не самым удачным подходом.

Параметризованные тесты — это отличный инструмент, который позволяет добиться хорошего покрытия тестов с минимумом усилий. В этом случае добавление еще одно тест-кейса в существующий код — это дело буквально нескольких секунд. К тому же, можно воспользоваться чудо паттерном "Object Mother" и выделить отдельные методы, создающие тестовые данные:

class CustomObjectMother
{
  public static IEnumerable GetTestCasesForYouSpecificCase()
  {
     yield return new TestCaseData("init1", "do1").Returns(0);
     yield return new TestCaseData("init2", "do2").Returns(1);
  }
}


Теперь, если у нас будет несколько тестов, которым подходят эти данные, то можно будет их использовать несколько раз:

[TestCaseSource("CustomObjectMother.GetTestCasesForYouSpecificCase")]
public int Test_That_Do_Produces_Expected_Result(string initData, string doData)
{}

[TestCaseSource("CustomObjectMother.GetTestCasesForYouSpecificCase")]
public int Another_Test_With_The_Same_Arguments(string initData, string doData)
{}


> Насколько будет удобно отлаживать во втором случа?

Если у вас есть решарпер, то это сделать очень просто:
http://files.rsdn.org/34036/Parametrized.png

В случае VS2012+, отлаживать тесты тоже просто. Ставим NUnit Test Adapter, в результате можно будет использовать для отладки встроенный Test Explorer:

http://files.rsdn.org/34036/Parameterized2.png

С Новым Годом
gravatar
Аноним
03.01.2014 08:49
Здравствуйте, SergeyT., Вы писали:

ST>Здравствуйте, Аноним, Вы писали:



А>>Nunit

А>>Есть вот такой метод для теста
А>>Как лучше, оставить как есть или сделать через параметры и указывать все значения init1, do1, 0, 1 — через аттрибуты
А>>Насколько это удобно будет отлаживать во 2м случае ?

ST>Конечно здесь явно напрашиваются параметризованные тесты, ведь по сути, здесь не один тест, а два.


ST>С Новым Годом



Спасибо, а такой момент еще возник.

Например в тесте делается


public void TestA(string init)
{
   var a = new A(init);
   
   Assert.AreEquals( A.Property1, 1 );
   Assert.AreEquals( A.Property2, "2" );

}



Можно ли сделать


public A TestA( string init )
{
   return new A(init);
}


А проверку полей и property у A указать также в new TestCaseData("init1").Returns(???);
Только вот не совсем понятно что нужно будет в Returns описать.