EventWaiter – testowanie zdarzeń

Dzisiaj chciałbym zaprezentować klasę EventWaiter. Znalazłem ją w repozytorium Roslyn na GitHub i w niektórych testach okazała się przydatna. Załóżmy, że mamy klasę eksponującą jakieś zdarzenie:

    class Sut
    {
        public event EventHandler Click;

        public void RaiseClickEvent()
        {
            Click?.Invoke(this,EventArgs.Empty);
        }
    }

Test zdarzenia mógłby wyglądać następująco:

        [Test]
        [Timeout(2000)]
        public void Test1()
        {
            // arrange
            var manualResetEvent = new ManualResetEvent(false);
            var sut = new Sut();

            sut.Click += (s, e) => { manualResetEvent.Set(); };

            // act
            sut.RaiseClickEvent();

            // assert
            manualResetEvent.WaitOne();
            Assert.Pass();
        }

Źródło klasy EventWaiter można znaleźć np. tutaj:
https://github.com/dotnet/roslyn/blob/master/src/Test/Utilities/Shared/FX/EventWaiter.cs

Kod:

  public sealed class EventWaiter : IDisposable
    {
        private readonly ManualResetEvent _eventSignal = new ManualResetEvent(false);
        private Exception _capturedException;

        ///
<summary>
        /// Returns the lambda given with method calls to this class inserted of the form:
        /// 
        /// try
        ///     execute given lambda.
        ///     
        /// catch
        ///     capture exception.
        ///     
        /// finally
        ///     signal async operation has completed.
        /// </summary>

        /// <typeparam name="T">Type of delegate to return.</typeparam>
        /// <param name="input">lambda or delegate expression.</param>
        /// <returns>The lambda given with method calls to this class inserted.</returns>
        public EventHandler<T> Wrap<T>(EventHandler<T> input)
        {
            return (sender, args) =>
            {
                try
                {
                    input(sender, args);
                }
                catch (Exception ex)
                {
                    _capturedException = ex;
                }
                finally
                {
                    _eventSignal.Set();
                }
            };
        }

        ///
<summary>
        /// Use this method to block the test until the operation enclosed in the Wrap method completes
        /// </summary>

        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool WaitForEventToFire(TimeSpan timeout)
        {
            var result = _eventSignal.WaitOne(timeout);
            _eventSignal.Reset();
            return result;
        }

        ///
<summary>
        /// Use this method to block the test until the operation enclosed in the Wrap method completes
        /// </summary>

        /// <param name="timeout"></param>
        /// <returns></returns>
        public void WaitForEventToFire()
        {
            _eventSignal.WaitOne();
            _eventSignal.Reset();
            return;
        }

        ///
<summary>
        /// IDisposable Implementation.  Note that this is where we throw our captured exceptions.
        /// </summary>

        public void Dispose()
        {
            _eventSignal.Dispose();
            if (_capturedException != null)
            {
                throw _capturedException;
            }
        }
    }

Dzięki temu wrapperowi, nasz kod może wyglądać teraz tak:


        [Test]
        [Timeout(2000)]
        public void Test1a()
        {
            // arrange
            var waiter=new EventWaiter();            
            var sut = new Sut();
            sut.Click += waiter.Wrap<EventArgs>((sender, args) => { Assert.Pass()});

            // act
            sut.RaiseClickEvent();

            // assert
            waiter.WaitForEventToFire();
        }

Powyższy przykład jest prosty. W praktyce musimy wciąć pod uwagę różne scenariusze – np. gdy wyjątek jest wyrzucany albo musimy sprawdzić konkretne parametry zdarzenia. W takich sytuacjach, powyższy wrapper jest przydatny.

NUnit 3 – testy wykonywane równolegle

Wersja nUnit 3.0 wspiera wykonywanie testów równolegle.  Jeśli mamy testy integracyjne albo akceptacyjne, wtedy wykonywanie ich równolegle, w znaczący sposób może przyśpieszyć  CI. W przypadku testów jednostkowych nie ma już to takiego znaczenia, bo i tak powinny one wykonywać się szybko.

Zaczynamy oczywiście od instalacji pakietu nuget NUnit 3. Załóżmy, że mamy następujące, czasochłonne do wykonania testy:

   [TestFixture]
    public class Tests1
    {
        [Test]
        public void Test1()
        {
            Console.WriteLine("Test 1 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 1 - end");
        }
    }

    [TestFixture]
    public class Tests2
    {
        [Test]
        public void Test2()
        {
            Console.WriteLine("Test 2 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 2 - end");
        }
    }

    [TestFixture]
    public class Tests3
    {
        [Test]
        public void Test3()
        {
            Console.WriteLine("Test 3 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 3 - end");
        }
    }

    [TestFixture]
    public class Tests4
    {
        [Test]
        public void Test4()
        {
            Console.WriteLine("Test 4 - start");
            Thread.Sleep(1000);
            Console.WriteLine("Test 4 - end");
        }
    }

Jeśli wykonamy je teraz, zostaną one odpalone w sposób sekwencyjny:

2

Czas wykonania to około 5 sekund, ponieważ domyślnie nie są one uruchamiane równoległe.
W Assembly.cs możemy umieścić globalny atrybut, który umożliwi ich zrównoleglenie, tzn.:

[assembly: Parallelizable(ParallelScope.Fixtures)]

Wynik:

1

Widzimy, że czas ich wykonania zmalał do 2 sekund.

Jeśli jakiś test chcemy wyłączyć z zrównoleglenia, wtedy wystarczy umieścić następujący atrybut:

[Parallelizable(ParallelScope.None)]

Jak widać, atrybut możemy stosować zarówno globalnie jak i selektywnie na konkretnych testach. Dobrze napisane testy nie powinny zależeć od kolejności ich wykonywania, zatem umieszczenie atrybutu Parallelizable globalnie jest rozsądnym podejściem.
Domyślna liczba wątków służąca do odpalenia testów zależy od procesora, a konkretnie liczby rdzeni. Możliwie jest jednak ręczne sterowanie liczbą wątków za pomocą następującego atrybutu:

[assembly:LevelOfParallelism(5)]

Warto również wspomnieć, że na dzień dzisiejszy nie istnieje możliwość wykonania konkretnych testów (metod) równolegle. Innymi słowy, możliwe jest zrównoleglenie wyłącznie klas (TestFixture).

Fuslogvw a assembly binding

Czasami proste debugowanie za pomocą Visual Studio nie wystarcza. Sposób w jaki biblioteki są ładowane zależy od wielu czynników i plików konfiguracyjnych. Jeśli np. nasza aplikacja wyrzuca wyjątek “MissingMethodException”, a w czasie debugowania wszystko działa jak należy, wtedy możliwe, że mamy problemy związane z assembly binding.

Narzędzie Fuslogvw wchodzi w skład Visual Studio i pozwala prześledzić jakie kolejno biblioteki ładowane są. Dzięki temu poznamy ich lokalizacje oraz wersje.

W celu uruchomienia fuslogvw, odpalamy najpierw wiersz poleceń Developer Command Propmpt (koniecznie jako administrator):
1Następnie wpisujemy “Fuslogvw.exe”, co spowoduje uruchomienie narzędzia:
2

W “Settings” możemy ustawić czy chcemy wyłącznie logować błędy czy wszystkie wiązania:
3

Następnie stwórzmy jakaś aplikację (np. ConsoleApp) w celu zobaczenia co zaloguje Fuslogvw. Po odpaleniu przykładowej aplikacji naciskamy “Refresh” w Fuslogvw:
4

Na ekranie zobaczymy kilka nowych wpisów. Klikając na jedno z nich przejdziemy do szczegółów:
5

W szczegółach widzimy wyraźnie jaka biblioteka jest ładowana i skąd. Z kolei jeśli jakieś biblioteki nie można załadować, wtedy logi będą wyglądać następująco:
6

Na screenshocie można zauważyć, które  ścieżki są kolejno brane pod uwagę, gdy pliku dll nie ma w głównym katalogu aplikacji.

LESS: rozszerzenia

Dzisiaj kolejne udogodnienie w CSS dostarczane przez LESS. W klasycznym CSS nie ma możliwości dziedziczenia klas. Jeśli chcemy, aby klasa B miała właściwości klasy A oraz kilka rozszerzających wtedy zwykle musimy duplikować kod.
W LESS rozszerzenia definiuje się następująco:

.childClass {
  &:extend(.baseClass);
  background: blue;
}

.baseClass {
  color: red;
}

Na wyjściu mamy:

.childClass {
  background: blue;
}
.baseClass,
.childClass {
  color: red;
}

Inna składnia to:

.childClass {
  background: blue;
}

.baseClass {
  color: red;
}

.childClass:extend(.baseClass){}

Więcej informacji znajduje się w dokumentacji. Na blogu zwykle planuję tylko umieszczać kilka przykładów jako wprowadzenie.

LESS: Mixins

Dzisiaj kolejna przydatna konstrukcja LESS. Często zachodzi potrzeba stworzenia klasy na podstawie kilku innych klas. Załóżmy, że mamy:

.class1
{
  color:red;
}
.class2
{
  font-size:10px;
}
.finalClass
{
  color:red;
  font-size:10px;
  
  border-color:blue;
}

FinalClass składa się zarówno z class1 jak i class2. Ponadto rozszerza możliwości o border-color. Za pomocą mixin możemy kod skrócić do:

.class1
{
  color:red;
}
.class2
{
  font-size:10px;
}
.finalClass
{
  .class1();
  .class2();
  
  border-color:blue;
}

Oczywiście w praktyce przydatne jest to, gdy klasy mają więcej właściwości niż jedna. W przypadku jednej właściwości lepiej skorzystać ze zmiennych.

Powyższy mixin wykona się do wspomnianych wcześniej stylów:

.class1 {
  color: red;
}
.class2 {
  font-size: 10px;
}
.finalClass {
  color: red;
  font-size: 10px;
  border-color: blue;
}

Możliwe jest również zadeklarowanie mixin za pomocą nawiasów ():

.class1()
{
  color:red;
}
.class2()
{
  font-size:10px;
}
.finalClass
{
  .class1();
  .class2();
  
  border-color:blue;
}

Różnica polega na tym, że na wyjściu nie pojawią się .class1\.class2:

.finalClass {
  color: red;
  font-size: 10px;
  border-color: blue;
}

Do mixin można przekazać parametry:

.class1(@color)
{
  color:@color;
}

.finalClass
{
  .class1(blue);
    
  border-color:blue;
}

Analogicznie, parametry mogą przyjmować domyślne wartości:

.class1(@color:green)
{
  color:@color;
}

.finalClass
{
  .class1();
    
  border-color:blue;
}

Należy pamiętać, że jeśli chce się przekazać kilka parametrów należy je oddzielić średnikiem tzn. @color;@color2 itd.

Tak jak w C#, parametry można przekazywać za pomocą nazwy czyli zamiast .class(red) można .class(@color:red). Do dyspozycji mamy również specjalny parametr o nazwie @arguments, który po prostu zawiera listę wszystkich argumentów:

.class1(@width;@style;@color)
{
  border:@arguments;
}

.finalClass
{
  .class1(@width:2px;@style:solid;@color:red);
    
  border-color:blue;
}

Czasami zachodzi potrzeba odpalenia różnych mixin w zależności od kontekstu, np. używanego urządzenia. Spójrzmy na następujący kod:

.class1(mobile)
{
  font-size:1px;
}
.class1(desktop)
{
  font-size:2px;
}


.finalClass
{
  .class1(mobile);
    
  border-color:blue;
}

Zdefiniowaliśmy tutaj różne mixin w zależności od typu urządzenia. Przekazując jako parametr mobile, ustawimy rozmiar czcionki na 1. Na wyjściu pojawi się zatem:

.finalClass {
  font-size: 20px;
  font-size: 1px;
  border-color: blue;
}

Jeśli zadeklarujemy pierwszy parametr jako zmienną wtedy uzyskamy generyczną klasę:

.class1(@device)
{
  border-width:4px;
}

.class1(mobile)
{
  font-size:1px;
}
.class1(desktop)
{
  font-size:2px;
}

.finalClass
{
  .class1(mobile);
    
  border-color:blue;
}

W powyższym przypadku “mobile” zostanie dopasowany do dwóch klas:

.finalClass {
  border-width: 4px;
  font-size: 1px;
  border-color: blue;
}

Jak widzimy, mixins mogą w znaczącym stopniu skrócić arkusze CSS poprzez unikanie duplikacji kodu.

LESS css – wprowadzenie, zmienne

Na blogu rzadko poruszam tematy CSS, ale czasami nawet jak ma się bardzo małą warstwę prezentacji, warto zainwestować trochę czasu w poznanie nowych bibliotek.

Dzisiaj chciałbym przedstawić LessCss.  Biblioteka stanowi pewnego rodzaju pre-processor, który rozszerza możliwości klasycznego CSS. Na wyjściu zatem pojawi się zwykły CSS, który jest obsługiwany przez wszystkie przeglądarki. Sprawą “kompilacji”, zajmiemy się w innym wpisie, ponieważ istnieje wiele sposobów. Jednym z nich jest np. kompilowanie za pomocą  JavaScript po stronie klienta. W tym poście będę korzystał z narzędzia online, które można znaleźć tutaj.

Załóżmy, że mamy kilka klas, które korzystają z tego samego koloru:


.customClass1
{
  color:red;
}

.customClass2
{
  color:red;
}

.customClass3
{
  color:red;
}

Za pomocą LESS możemy zdefiniować zmienną:

@customColor: red;

.customClass1
{
  color:@customColor;
}

.customClass2
{
  color:@customColor;
}

.customClass3
{
  color:@customColor;
}

Po w klejeniu wspomniany wcześniej edytor online, zobaczymy, że na wyjściu @customColor zostanie zastąpiona wartością Red. Wszelkie zmienne w Less definiujemy za pomocą @. Zmiana wartości odbywa się za pomocą znaku ‘:’ (dwukropek).

Wszelkie stałe zatem można w łatwy sposób umieścić tylko w jednym miejscu. Zmienne nie ograniczają się jedynie do wartości. Możliwe jest również umieszczenie selektorów CSS w nich, tzn.:

@customSelector: .customClass;

@{customSelector}
{
  color:red;
}

Po kompilacji:

.customClass {
  color: red;
}

Zmienna ładowane są w sposób “lazy-loading. W praktyce oznacza to, że nie muszą być deklarowane przed ich użyciem. Poniższy kod również wygeneruje taką samą odpowiedź:

@{customSelector}
{
  color:red;
}

@customSelector: .customClass;

Osobiście uważam, że może z tego wyniknąć wiele problemów.

W dokumentacji znalazłem również informacje, że możliwe jest korzystanie ze zmiennej jako nazwy dla kolejnej zmiennej. Spójrzmy na następujący kod:

@varName: 'test';
@test: 'red';

.customClass
{
  color:@@varName
}

Po kompilacji:

.customClass {
  color: 'red';
}

Moim zdaniem bardzo niebezpieczna konstrukcja. Podwójny operator @ wyciągnie najpierw wartość ze zmiennej varName, a potem użyje jej jako docelowej zmiennej.

W następnych wpisach skupie się na pozostałych możliwościach LESS oraz na kompilacji LESS do normalnego CSS.

C# 7.0 – Tuples

Klasa (immutable) Tuple istniała aż od .NET Framework 4.0. W C# 7.0 mamy jednak wsparcie dla tuple od strony języka. Jednym z problemów klasy Tuple było, że każda właściwość nazywała się kolejno Item1, Item2 itp.

Przykład:

    class Program
    {
        private static void Main(string[] args)
        {
            var tuple = GetFirstAndLastName();

            Console.WriteLine(tuple.Item1);
            Console.WriteLine(tuple.Item2);
        }

        private static Tuple<string,string> GetFirstAndLastName()
        {
            var tuple = new Tuple<string, string>("Piotr", "Zielinski");

            return tuple;       
        }
    }

W wersji 7.0, powyższy kod możemy przepisać do:

    class Program
    {
        private static void Main(string[] args)
        {
            var tuple = GetFirstAndLastName();

            Console.WriteLine(tuple.firstName);
            Console.WriteLine(tuple.lastName);
        }

        private static (string firstName, string lastName) GetFirstAndLastName()
        {
            var fullName = (firstName: "Piotr", lastName: "Zielinski");

            return fullName;
        }
    }

Składnia dużo czytelniejsza ponieważ nie operujemy już na Item1 i Item2. Zobaczmy co się kryje za tym nowym “Tuple” po dekompilacji:

  internal class Program
  {
    // Method .ctor with token 06000003
    public Program()
    {
      base.\u002Ector();
    }

    // Method Main with token 06000001
    private static void Main(/*Parameter with token 08000001*/string[] args)
    {
      ValueTuple<string, string> firstAndLastName = Program.GetFirstAndLastName();
      Console.WriteLine(firstAndLastName.Item1);
      Console.WriteLine(firstAndLastName.Item2);
    }

    // Method GetFirstAndLastName with token 06000002
    private static ValueTuple<string, string> GetFirstAndLastName()
    {
      return new ValueTuple<string, string>("Piotr", "Zielinski");
    }
  }

Całość opiera się na zwykłej strukturze ValueTuple<string, string>. Wygląda to bardzo analogicznie do starego Tuple<T1,T2>. Zaglądając do źródeł ValueTuple, przekonamy się, że klasa jest immutable i  przeładowuje metody typu Equals oraz GetHashCode. Oznacza to, że typ doskonale nadaję się jako klucz do słowników.

Powyższy kod można przetestować używając Visual Studio ’15’ preview 3,  który jest dostępny tutaj.

ASP.NET Core – wstrzykiwanie zależności

ASP.NET Core ułatwia w znaczący sposób IoC. Przede wszystkim wbudowano w framework dosyć prostą implementację IoC. Oznacza to, że w wielu przypadkach nie trzeba już instalować zewnętrznych framework’ow takich jak AutoFac.  W pliku Startup znajdziemy metodę ConfigureServices:

        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddApplicationInsightsTelemetry(Configuration);

            services.AddMvc();
        }

Jeśli chcemy zarejestrować instancję jako singleton wtedy wystarczy:

services.AddSingleton<ITest, ConcreteTest>();

Nic więcej nie trzeba konfigurować. Instancja automatycznie zostanie wstrzyknięta do kontrolerów jak i widoków. Sprawa w przypadku kontrolerów wygląda prosto i wystarczy po prostu stworzyć konstruktor:

        public HomeController(ITest test)
        {
            _test = test;
        }

W przypadku widoków, również możemy korzystać z wstrzykniętych instancji:

@using Microsoft.Extensions.Configuration
@inject ITest test

@{
    ViewData["Title"] = "About";
}

<h2>@ViewData["Title"].</h2>


<h3>@ViewData["Message"]</h3>




@test.GetText()


AddSingleton tworzy oczywiście pojedynczą instancję. Istnieje również metoda AddTriansient:

services.AddTransient<ITest, ConcreteTest>();

Tworzy ona nową instancję za każdym razem, gdy dochodzi do wstrzyknięcia.

Inny sposób to AddScoped:

services.AddScoped<ITest, ConcreteTest>();

AddScoped będzie współdzielić instancję w ramach tego samego zapytania. Przydatne, kiedy mamy wiele klas do których wstrzykujemy ten sam typ. W wielu przypadkach nie ma potrzeby tworzenia osobnych instancji.

Cykl BDD\TDD

Zarówno o BDD, jak i TDD wiele razy już pisałem. Najważniejszą rzeczą w TDD jest sekwencja red-green-refactor.  Zwykle BDD\TDD przybiera następującą postać:

  1.  Zaczynamy od etapu BDD. Definiujemy wymagania za pomocą języka rozumianego zarówno przez programistów jak i jak BA\PO. Za pomocą Specflow możemy zdefiniować np. następujący test:
        Given I have entered 50 into the calculator
        And I have entered 70 into the calculator
        When I press add
        Then 120 should be displayed on the screen
    
  2. W celu zaimplementowania powyższej specyfikacji, rozpoczynamy cykl TDD. W tym celu tworzymy serie klasycznych testów jednostkowych. Cykl TDD trwa do momentu, kiedy specyfikacja z punktu pierwszego zostanie zaimplementowana.
  3. Definiujemy następną specyfikację, rozpoczynając zatem kolejny cykl TDD.

Innymi słowy, na każdą specyfikacje BDD, przypada ileś testów TDD. Wszystko jest wykonywane na zasadzie red-green-refactor. Definiując specyfikację BDD w punkcie pierwszym, oczywiście taki test będzie czerwony dopóki nie przeprowadzimy cyklu TDD.

Testy UI: Wzorzec PageObject

O testach UI, szczególnie w SpecFlow pisałem już kilka razy. Zawsze korzystałem z wzorca PageObject, chociaż nie wiedziałem, że ma on swoją nazwę. Czasami mam wrażenie, że na proste rzeczy wymyśla się “wzorce”. Muszę przyznać jednak, że  uproszcza to często komunikację między programistami. Wzorce w końcu stanowią pewnego rodzaju słownictwo dla programistów. Zamiast opisywać coś w kilku zdaniach, można powiedzieć po prostu nazwę wzorca.

PageObject pattern polega na tym, że pisząc testy jednostkowe, opakowujemy stronę w obiekty C#.  Początkujący programiści często piszą testy  w stylu:

        [Test]
        public void Query_ShouldBe_Persisted_When_SearchButtonIsClicked()
        {
            IWebDriver driver = new ChromeDriver();
            driver.Navigate().GoToUrl("http://www.bing.com");

            var textBox = driver.FindElement(By.Id("sb_form_q"));
            textBox.SendKeys("piotr zielinski c#");

            var searchButton = driver.FindElement(By.Id("sb_form_go"));
            searchButton.Click();

            string query = driver.FindElement(By.Id("sb_form_q")).GetAttribute("value");
            Assert.That(query,Is.EqualTo("piotr zielinski c#"));
        }

Test jest trudny w zrozumieniu oraz czasochłonny w utrzymaniu. Idealny test powinien być czytany jak skrypt opisujący kolejne akcje. W PageObject opakowujemy strony w obiekty c#. W naszym przypadku stworzymy dwa obiekty, SearchForm oraz SearchResults:

   public class SearchForm
    {
        private readonly IWebDriver _webDriver;

        public SearchForm(IWebDriver webDriver)
        {
            _webDriver = webDriver;
        }

        public SearchResults Search(string query)
        {
            var textBox = _webDriver.FindElement(By.Id("sb_form_q"));
            textBox.SendKeys(query);

            var searchButton = _webDriver.FindElement(By.Id("sb_form_go"));
            searchButton.Click();

            return new SearchResults(_webDriver);
        }        
    }
    public class SearchResults
    {
        private readonly IWebDriver _webDriver;

        public SearchResults(IWebDriver webDriver)
        {
            this._webDriver = webDriver;
        }

        public string GetQuery()
        {
            return _webDriver.FindElement(By.Id("sb_form_q")).GetAttribute("value");
        }
    }

Test zatem wygląda teraz następująco:

            IWebDriver driver = new ChromeDriver();
            driver.Navigate().GoToUrl("http://www.bing.com");
            const string query = "Piotr zielinski c#";
          
            var searchForm=new SearchForm(driver);
            var searchResults = searchForm.Search(query);

            Assert.That(searchResults.GetQuery(), Is.EqualTo(query));

Zwykle opakowuję również sterownik czyli interfejs IWebDriver. Można stworzyć obiekt o nazwie np. BingWebsite który będzie stanowił bramkę do wszelkich testów. Celem jest, aby jakikolwiek kod Selenium nie znajdował się bezpośrednio w teście. Dzięki temu, ten sam kod może być wykorzystywany w różnych testach. Ponadto, przy skomplikowanych testach, kod jest dużo prostszy w rozumieniu ponieważ stanowi skrypt bez magicznych zmiennych.