Visual Studio 2015: Smart Unit Tests

Jeśli jeszcze nie ściągneliście VS 2015, to zapraszam:

http://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs.aspx

Smart Unit Tests to sposób automatycznego wygenerowania scenariuszy dla testów jednostkowych. Wiele o tym już na blogu jak i w artykułach na MSDN pisałem, a konkretnie o Pex & moles. Chciałbym dzisiaj jednak zaprezentować wbudowaną funkcję w VS 2015. Nie wymaga ona instalacji zewnętrznych narzędzi.

Na początku od razu poważna wada.. Póki co, wspierany jest wyłącznie MSTest. Mam nadzieję, że zmieni się to w oficjalnym wydaniu bo inaczej większość osób nie będzie mogła z tego korzystać.

Załóżmy, że zaimplementowaliśmy już jakąś metodę i chcemy wygenerować test:

public double AnyMethod(int a,int b,double c,string text)
{
  if (a == 3)
      return 1;
  else if (b == a && a == 1)
      return 2;
  else if (b == (int)c && a == 6 && text == "Hello")
      return 3;
  else if (Int32.Parse(text) == a)
      return 4;
  else if (c == a + b)
      return 5;

  return 6;
}

Smart Unit tests postara się wygenerować tak dane wejściowe, aby każda gałąź została pokryta. Zaznaczamy zatem metodę i z menu kontekstowego wybieramy Smart Unit Test:

image

Zostanie wyświetlone następujące okno ze scenariuszami:

image

Widzimy po kolumnie result, że wszystkie scenariusze zostały wygenerowane – wartości od 1 do 6 (wszystkie możliwe ścieżki).

Ponadto, część scenariuszy generuje wyjątki. Wiąże się to z tym, że nie można przekazać tekstu do parametru text i potem wywoływać Int32.Parse. Klikając na każdym z nich, po prawej stronie wyświetli się wygenerowany test:

image

Możemy dowolny scenariusz zapisać do pliku np.:

public partial class SampleTest
{
   [TestMethod]
   [PexGeneratedBy(typeof(SampleTest))]
   public void AnyMethod898()
   {
       double d;
       Sample s0 = new Sample();
       d = this.AnyMethod(s0, 6, 0, 0, "Hello");
       Assert.AreEqual<double>(3, d);
       Assert.IsNotNull((object)s0);
   }
}

Oczywiście możemy wszystkie pozycje zaznaczyć i zapisać.

Powyższe okno również zawiera uwagi i wskazówki:

image

Warto zawsze przejrzeć listę bo czasami możemy dowiedzieć się czegoś, czego nie spodziewaliśmy się po naszym kodzie.

Zmodyfikujmy teraz trochę AnyMethod, aby sprawdzał, że text jest zawsze liczbą:

public double AnyMethod(int a, int b, double c, string text)
{
  if (text == null || !text.All(x => char.IsDigit(x)))
      throw new ArgumentException();

  if (a == 3)
      return 1;
  else if (b == a && a == 1)
      return 2;
  else if (b == (int)c && a == 6 && text == "Hello")
      return 3;
  else if (Int32.Parse(text) == a)
      return 4;
  else if (c == a + b)
      return 5;

  return 6;
}

Po ponownym wygenerowaniu scenariuszy zobaczymy:

image

Smart Unti Test rozpoznał sam, że wyrzucenie ArgumentException jest spodziewanym wynikiem, gdy przekazujemy tekst zamiast liczby. Niestety nie uwzględniliśmy przypadku, gdy Text jest pusty, stąd 4 testy zakończone błędem. Zmodyfikujmy kod i odpalmy analizę ponownie:

public double AnyMethod(int a, int b, double c, string text)
{
  if (string.IsNullOrEmpty(text) || !text.All(x => char.IsDigit(x)))
      throw new ArgumentException();

  if (a == 3)
      return 1;
  else if (b == a && a == 1)
      return 2;
  else if (b == (int)c && a == 6 && text == "Hello")
      return 3;
  else if (Int32.Parse(text) == a)
      return 4;
  else if (c == a + b)
      return 5;

  return 6;
}

image

Jak widzimy, wszystkie gałęzie zostały pokryte, włączając te, które wyrzucają ArgumentException.

Podsumowując… Przede wszystkim, należy pamiętać, że pokrycie kodu 100% nie znaczy, że wszystko zostało przetestowane. Sprawdza to, czy każda gałąź zostanie wywołania, a nie czy każda kombinacja gałęzi jest pokryta.

Kolejna wątpliwość to bardzo popularne dzisiaj TDD. Tak naprawdę, kod powinien być pokryty już testami, jak kończymy implementację czegoś.

Dla mnie największą jednak wadą jest brak wsparcia dla nUnit. Gdybym mógł z niego korzystać, to nawet w połączeniu z TDD może to się przydać. Zawsze mamy legacy kod i możemy popełnić jakiś błąd więc Smart Unit Test byłoby fajnym sposobem na weryfikację naszego kodu. Innymi słowy, nie korzystałbym z tego jako coś bazowego dla moich testów, ale wyłącznie uzupełniającego.

Co prawda, nie testowałem tego jeszcze, ale podobno Microsoft Pex oraz Code Contracts współpracują ze sobą, co oznacza, że moglibyśmy generować bardziej trafne scenariusze użycia za pomocą Smart Unit Test.

6 thoughts on “Visual Studio 2015: Smart Unit Tests”

  1. Próbówałem Smart Unit Test z Code Contracts i nie bardzo działa. Np. dodałem contract:
    Contract.Requires(text != null);

    Generowane test casy się nie zmieniły. Nadal generuje testy z przypadkami gdzie text == null.

    Może trzeba coś gdzieś ustawić? Ja nie znalazłem takiej opcji.

  2. Wiesz to jeszcze wersja preview jest a nie oficjalna.
    Po za tym, to jest Smart Unit Tests a nie czysty Pex.

    Tak czy inaczej, mam nadzieje, ze bedzie dzialac to poprawnie w finalnej wersji. Czasami po prostu nie warto generowac tylu unit testow i bedzie tworzyl sie balagan…

  3. Na pewno jest to krok w dobrą stronę. Wiadomo, że nie jest to jeszcze idealne rozwiązanie, ale z czasem pewnie wyrośnie coś bardziej zaawansowanego. Nawet w obecnej postaci na pewno usprawni tworzenie unit testów.

Leave a Reply

Your email address will not be published.