Jeszcze słowo o TDD

O TDD napisano wiele, sam napisałem całkiem sporo i mówiłem całkiem sporo podczas kilku prelekcji. Używam TDD od ponad 5 lat już. Powinienem być super mega ninja pro TDD master. Mimo tego jakiś czas temu, pisząc bardzo prosty kod, na prawdę super prosty, naszła mnie taka refleksja:

Jest zielone, jest ok.

[Fact]
public void Example_test()
{
    _pinger.Ping().Returns(c =>
    {
        throw new Exception();
    });
    Assert.DoesNotThrow(()=>_monitor.CheckAvaliability());
    _destinationSystem.Received(1).Ping(Arg.Is<IDiagnostics>(diag => diag.State == ""));
}

Powyższy kawałek kodu używa NSubstitute (.Ping().Returns(c=>…..) do mockownia. Oraz XUnit-a do testów. Napisałem test jak wyżej, napisałem kod. Niby wszystko zielone, niby ok. Jakimś cudem jednak pokusiło mnie, żeby dorzucić AutoData. AutoData to taki sprytny atrybut, który pozwala generować dane testowe. W moim przypadki Message z wyjątki ma znaczenie, dlatego stwierdziłem, że Message można spokojnie generować – tutaj kod jest taki, że mam pudełko, które jak zrobi coś złego to to złe ma wyjść z drugiej strony – case dla AutoData jak malowany.

[Theory,AutoData]
public void Example_test(string exceptionMessage)
{
    _pinger.Ping().Returns(c =>
    {
        throw new Exception(exceptionMessage);
    });<
    Assert.DoesNotThrow(()=>_monitor.CheckAvaliability());
    _destinationSystem.Received(1).Ping(Arg.Is<IDiagnostics>(diag => diag.State == exceptionMessage));
}

No i zonk!!! Test już nie bardzo to przechodzi. Pomyślałem, bez jaj, przecież implementacja jest tak prosta, że tego nie da się zepsuć – nawet nie wiem po co pisałem na to test, ale nie uprzedzajmy faktów…. Debug testu i….. okazało się, że jednak w kodzie gdzie łapię wyjątek, to oprócz logowania tak jak to powinno być to już message-a  nie przepisuję. Kto by pomyślał.

Testy jednostkowe nie dają 100% gwarancji, że powstanie kod bez bugów, nie dają nawet jakiejkolwiek gwarancji, co jednak dają, to dużo wyższą szansę, że powstały kod będzie miał mniej bugów niż bez testów. W moim przypadku, okazało się, ze prosta refaktoryzacja – lub bez AutoData dodanie kilku przypadków testowych, pozwoliła złapać buga zanim kod poszedł na produkcję.

100 dni kodowania

Założenia:

codziennie przez 100 dni będę pisał kawałek kodu

kod musi zostać opublikowany na GitHub-ie

zmiana musi mieć jakąś wartość – nie liczy się commit  z samymi zmianami nazw

wszędzie gdzie to możliwe, nowy kod powinien wprowadzać zmianę w interfejsie użytkownika (bądź api)

kod pisany w pracy się nie liczy (nie leci do GitHuba)

minimum 30 minut kodowania

Historia:

Jakiś czas temu dostałem link do bloga John-a Resig-a – tego który jest ojciem jQuery gdzie opisuje swoje 180 dni z pisaniem kodu – CODZIENNIE. Zainspirowała go Jennifer Dewalt,  która w ramach nauki postanowiła przez 180 dni tworzyć strony www. Stwierdziłem, że dlaczego by samemu nie spróbować. No i tak postanowiłem codziennie kodować. Do podobnego projektu podchodziłem ale w fotografii – 365 zdjęć, codziennie minimum jedno zdjęcie. Niestety nie udało się wytrwać, dlatego do obecnego projektu zmieniłem założenia, 100 dni (a jak się uda przeżyć 100 to 180) – tyle musi się udać. Na dzień dzisiejszy jestem na dniu 14-stym, jest ok, jest moc, trzeba pomyśleć co się napisze, trzeba to dobrze zaplanować bo w ciągu tygodnia jakoś łatwiej idzie ale  weekend muszę dobrze zaplanować kiedy i co napiszę aby spełnić wymagania.

Trzymajcie kciuki, aby się udało.

 

Aktualizacja:

  • Verbalizer – zamiana liczby całkowitej na słownie (aktualnie wspiera wartości do milionów), C#
  • FizzBuzz – przykładowa aplikacja webowa z odseparowanymi warstwami, ASP.NET MVC5 + AngularJS + Autofac + WebApi2
  • BreakOut – pierwsze eksperymenty z Unity w celu zbudowania klasyka – Breakout – teraz wiem, że powstanie z tego coś zupełnie innego, Unity + X
  • Mono – eksperymenty z mono, czyli czy to w ogóle działa, czy działa na tym Nancy i pewnie jeszcze kilka innych rzeczy, do tej pory Mono, Nancy
  • X – Eksperymenty z czymś o czym za bardzo jeszcze nie mogę mówić (NDA) ale mam nadzieję, że niedługo będę mógł udostępnić filmik, repo już jest na githubie ale ciągle jeszcze mocno prywatne.

 

foto: Rodrigo Denúbila

Debuggowanie – Make Object ID

Czasem zwykłe metody debugowania nie wystarczają, czasem watch-e i sprawdzanie krok po kroku jest nie wystarczające. Czasem chciało by się sprawdzić wartość obiektu, do którego nie mamy referencji. No właśnie, wszystkie normalne narzędzia debuggowania jakie udostęnia Visual Studio pozwalają na oglądanie wszystkiego co mamy w zasięgu referencji albo gdzieś po callstack-u możemy się do “tego” dorwać. Co jednak jeśli i to za mało? Na pomoc Make Object ID. Zatrzymując program w momencie gdy mamy dostęp do rzeczonego obiektu (new NaszPodgladanyObject ??) wystarczy utworzyć sobie referencję 🙂

vsObjectId

Po dodaniu watch-a wystarczy z menu context-owego wybrać Make Object ID, co powoduje dodanie numerka do obiektu – takiego 1# (kolejna będzie 2#, 3# etc). Teraz możemy w watch-u oglądać obiekt 1#, co więcej przez całe życie programu ten obiekt będzie dostępny przez 1#, co więcej 1# możemy używać również w moim ulubionym immediate window Uśmiech

Debugowanie w Visual Studio

Ostatnio widzę dużo wpisów na temat debugowania aplikacji. Nie trafiłem jednak na opis dwóch rzeczy, które bardzo tą czynność ułatwiają, mianowicie, zmiana kolejności wykonywania kodu oraz GetHashCode()

Zmiana kolejności wykonywania kodu

Czy zdarzyło Ci się podczas debugowania przejechać o tą jedną linijkę za daleko? Nic prostszego, chwyć żółtą strzałkę i przesuń kilka linijek do tyłu i wykonaj kod jeszcze raz. To jest tak proste, że aż niebywałe, że niektórzy o tym nie wiedzą. Teraz już wiecie.

vsdebugger.gif

Możemy przesuwać się na początek i na koniec funkcji, do przodu i do tyłu. Krok dalej to w przypadku wyjątku, który zatrzymał nam program, możemy przenieść się na koniec funkcji, wyjść z niej, cofnąć się linijkę do góry (w kawałku kodu, który tą funkcję wywołał) i wywołać jeszcze raz, próbując zrozumieć dlaczego program “się sypnął”. Dzięki czemu nie trzeba restartować aplikacji i przeklikiwać się. Rozwinięciem tego jest możliwość edycji kodu w trakcie debugowania. Szczęśliwcy z VS2008 (bodajże) na maszynach 32bit mogą to robić od dawna. Jeśli używacie x64 to dopiero VS2013 pozwala modyfikować kod w locie. Świetna sprawa, oszczędza sporo czasu (chociaż ma swoje ograniczenia).

GetHashCode()

GetHashCode to funkcja, któraz zwraca nam unikalny (teoretycznie) identyfikator obiektu. Do czego to może być przydatne przy debugowaniu? Ano czasem jest tak, że kod robi coś dziwnego i za bardzo nie wiadomo dlaczego, bo niby jest ok ale działa dziwacznie. I jak już wszystko zawiedzie, to okazuje się, że warto sprawdzać Hash obiektów, bo może się okazać, że w jednej części aplikacji mamy jeden obiekt a w innej części drugi obiekt mimo tego, że myślimy, że to ten sam. Sam więcej niż raz wpadłem w taką pułapkę, że myślałem, że mam do czynienia z  jakimś obiektem danej klasy, a okazywało się, że gdzieś po drodze się podpinała inna instancja i tak naprawdę miałem te same dane ale inne referencje wewnątrz i koniec końców program działał trochę inaczej. Mi najwygodniej użyć do tego Immediate Window (ALT+CTRL+I) i po prostu klepię ?  nazwaZmiennej.GetHashCode(). Proste jak budowa cepa a bardzo skuteczne, zadziwiająco skuteczne.

Dając Ci te dwa (nowe) narzędzia, życzę owocnych łowów.

NSubstitute czyli lepsza wersja Moq

NSubstitute to (dla tych co nie znają jeszcze) taki Moq na sterydach. Sytuacja wygląda tak, mamy klasę, która potrzebuje jakiś zależności, mniej więcej tak:

  public class SomeClass
  {
    public SomeClass(INeedSomeStuff stuff)
    {
        // .......
    }
  }

  public interface INeedSomeStuff
  {
     string DoSomeStuff(string param);
     void DoSomeOtherStuff();
  }

Możemy użyć moq i napisać:

var moq = new Mock<INeedSomeStuff>();
moq.Setup(m => m.DoSomeStuff("Hello")).Returns(r => "World");

INeedSomeStuff someStuff = moq.Object;
var someObj = new SomeClass(someStuff);

lub za pomocą NSubstitue napisać dokładnie to samo tak:

var someStuff = Substitute.For<INeedSomeStuff>();
someStuff.DoSomeStuff("Hello").Returns("World");
            
var someObj = new SomeClass(someStuff);

poza tym, że pozbywamy się lambd, to jeszcze nie mamy dodatkowego .Object o którym trzeba pamiętać, ot mamy zamiennik naszej klasy. Ale to nie wszystko, jest jeszcze lepiej, NSubstitute działa od razu, więc nie trzeba robić setupów w miejscach, gdzie czasem moq tego wymaga ale najlepsze to kwiatek na jaki się nadziałem przy przechodzeniu z Moq na NSubstitute. Jest kawałek kodu, który zwraca kolorki z zadanej palety, po kolej – ColorGenerator. Metoda GetColor() zwraca kolor z tablicy. Za każdym wywołaniem bierze następny kolor. Tyle teorii. Sytuacja taka, że trzeba to zamockować:

 _mockColorGenerator.Setup(x => x.GetColor()).Returns(_colors[0])
     .Callback(() => _mockColorGenerator.Setup(x => x.GetColor()).Returns(_colors[1])
     .Callback(() => _mockColorGenerator.Setup(x => x.GetColor()).Returns(_colors[2])
     .Callback(() => _mockColorGenerator.Setup(x => x.GetColor()).Returns(_colors[3]))));

Może, za pomocą moq można to napisać lepiej no ale jest (było) i działało. W NSubstitute można to zapisać tak:

_colorGenerator.GetColor().Returns(_colors[0], _colors[1], _colors[2], _colors[3]);

Efekt ten sam tylko 6 lambd mniej, 3 callbacki mniej, ogólniej wielokronie czytelniej.

P.S. NSubstitute jest na nugecie więc instalacja jest bezproblemowa, dodatkowo można używać równolegle z moq i małymi kroczkami wycinać tego ostatniego.