Archiwum kategorii: 10Things

Daj Się Poznać, 10Things i restart

Daj Się Poznać, 10Things i restart

A więc konkurs Daj Się Poznać dobiegł końca, a więc czas na podsumowanie sukcesów i porażek.

Sukces

Zacząłem pisać blog-a i aplikację w Xamarin.Forms. Wreszcie usiadłem do tego tak na poważnie i starałem się to robić w miarę systematycznie. Wziąłem też udział w swoim pierwszym konkursie dla programistów ever… Niestety przyszła…

Porażka

Niestety dosięgła mnie tzw. proza życia i codzienne obowiązki, których nie umiałem pogodzić z blogiem, konkursem i projektem.

Jako, że jednym z moich celów jest spędzać jak najwięcej czasu z rodziną. Nie potrafiłem tego pogodzić, wieczorem niestety pojawiało się zmęczenie po całym dniu i na pewnym etapie coś w rodzaju wypalenia. Akurat w tym okresie praca 8h na etacie też dało mi bardzo w kość.

Niektórzy nazwą to wymówkami ale cóż takie życie i u mnie tak to wyglądało.

Co dalej

Pora się przeorganizować i zacząć wszystko na spokojnie od początku, iść do przodu zgodnie ze swoimi celami. Możliwe, że stworzę sobie listę coś na wzór Trzy poziomy.

Zrobiłem restart projektu i zacząłem pisać od początku tym razem spokojniej i mam nadzieję bardziej systematycznie. Będzie to obecnie to mój tzw. „pet project” robiony po godzinach i w wolnym czasie. Nic na siłę ale mam nadzieję, że tego nie porzucę.

Dzięki konkursowi spojrzałem na blog i to co robię po godzinach w bardziej dojrzały sposób w pewnym sensie też usystematyzowałem swoje plany.

Blog

Będę chciał się skupić na tym co umiem najlepiej i znam z autopsji, pisać o życiu programisty w światku aplikacji enterprise. Miłość do Xamarin.Forms nadal jest aktualna ale chciałbym to ująć również bardziej z perspektywy dużego biznesu.

10Things

Prace nad projektem będą trwały nadal w tym celu powstał nowy branch na GitHub. Powstała również nowa lista Issues.

Tylko pewnie tempo prac spadnie albo i nie poczekamy zobaczymy.

xUnit Theory: Jak używać InlineDate, ClassData lub MemberData

xUnit Theory: Jak używać InlineData, ClassData oraz MemberData

Ciąg dalszy cyklu o xUnit, oraz testowaniu aplikacji mobilnych w Xamarin.Forms.

Dzisiaj chciałbym omówić zastosowanie, oraz pokazać parę przykładów użycia Theory.

xUnit Theory: Jak używać InlineData, ClassData oraz MemberData

Czym jest Theory

Testy z atrybutem Theory umożliwiają nam przekazanie jako parametr danych wejściowych (może to być również kolekcja parametrów). Natomiast ich wynik jest poprawny tylko dla konkretnych dany wejściowych, czyli za jednym zamachem możemy przetestować pozytywne i negatywne przypadki.

Jak przekazać dane do metody

Żeby przekazać dane do metody możemy użyć jednego z 3 atrybutów InlineData, ClassData lub MemberData.

  • InlineData – umożliwia nam przekazanie danych typów prostych string, int, decimal, itd.
  • ClassData – umożliwia nam przekazanie typów złożonych
  • MemberData – umożliwia nam przekazanie typów złożonych z tą różnicą, że nie wymaga definiowania nowej klasy. Może to być dowolny obiekt, który zwraca IEnumerable

Przykłady użycia

Poniżej kilka przykładów implementacji każdego typu atrybutu.

InlineData

        [Theory]
        [InlineData("2017-04-15")]
        [InlineData("2017-04-16")]
        [InlineData("2017-04-17")]
        public async void CanGetDifferentProblemsForEachDayWhichIsNotNull(DateTime currentDate)
        {
            //Arrange
            IDataService service = new MockDataService();

            //Act
            Problem problem = await service.GetProblemByDateAsync(currentDate);

            //Assert
            Assert.NotNull(problem);
        }

ClassData

    public class TodoItemsTestData : IEnumerable<object[]>
    {
        private readonly List<object[]> data = new List<object[]>
        {
            new object[] { Guid.NewGuid(), string.Empty, false, null},
            new object[] { Guid.NewGuid(), "Buy tickets for movie", false, null },
            new object[] { Guid.NewGuid(), string.Empty, false, null },
            new object[] { Guid.NewGuid(), "Buy a milk", true, null },
        };

        public IEnumerator<object[]> GetEnumerator() => data.GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
....
        [Theory]
        [ClassData(typeof(TodoItemsTestData))]
        public async void CantAddTodoItemWithoutTitle(Guid id, string title, bool done, DateTime? dueDate)
        {
            //Arrange
            DataService service = new DataService();
            TodoItem item = new TodoItem { Id = id, Name = title, Done = done, DueDate = dueDate };

            //Act
            var ex = await Assert.ThrowsAsync<ArgumentException>(() => service.AddTodoItemAsync(item));

            //Assert
            Assert.IsType<ArgumentException>(ex);

MemberData

    public class TodoTheoryData<T> : TheoryData<T>
    {
        public TodoTheoryData(IEnumerable<T> data)
        {
            foreach (T t1 in data)
            {
                Add(t1);
            }
        }
    }
    public class DataServiceTests
    {
        private static TodoItem[] todoItems = new TodoItem[]
        {
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a milk", Done = false, DueDate = null},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a TV", Done = false, DueDate = null},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a new iPhone", Done = false, DueDate = DateTime.Today},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a pomodoro", Done = false, DueDate = null},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a bread", Done = false, DueDate = null}
        };

        public static TodoTheoryData<TodoItem> TodoItemsData { get; } = new TodoTheoryData<TodoItem>(todoItems);

        [Theory]
        [MemberData(nameof(TodoItemsData))]
        public async void InStorageAreFiveItems(TodoItem item)
        {
            //Arrange
            DataService service = new DataService();
            await service.AddTodoItemAsync(item);

            //Act
            IEnumerable<TodoItem> todoItems = await service.GetAllAsync();

            //Assert
            Assert.Equal(5, todoItems.Count());
        }
    }

Podsumowanie

Jak widzicie użycie Theory daje nam dużo benefitów i ułatwia nam testowanie aplikacji mobilnych napisanych w Xamarin.Forms ale i nie tylko.

Z użyciem xUnit możemy testować całą pulę aplikacji na platformie .Net od aplikacji Desktop, Mobile aż po Web.

Pomocne linki

Jeżeli chcecie poczytać coś więcej o xUnit Theory to odsyłam was do poniższych linków:

3 najważniejsze słowa w xUnit

3 najważniejsze słowa w xUnit

Aplikacje stają się coraz bardziej skomplikowane, zawierają mnóstwo logiki biznesowej dlatego testy jednostkowe w naszych aplikacjach są ich ważnym aspektem. Dzisiaj chciałbym wam przedstawić 3 najważniejsze słowa w xUnit.

3 najważniejsze słowa w xUnit

Fact, Theory, Assert – Arrange, Act, Assert

Każdy test powinien mieć odpowiednią strukturę. Dlatego ja zawsze dziele je na etap inicjalizacji Arrange, etap wykonania Act i etap porównania wyników Assert.

Przykładowa metoda do testów może mieć następującą strukturę

public void TestMethod1()
{
    //Arrange

    //Act

    //Assert
}

Fact

Jest to podstawowy typ testu w xUnit. W porównaniu do innych framework-ów każdy test stanowi odrębną jednostkę. W każdym z nich należy zainicjalizować wymagane komponenty jak również zapewnić obsługę rollback.

Poniższy przykład ma na celu przetestowanie warstwy serwisu naszej aplikacji i mechanizmu pobierania danych na konkretną datę.

Metoda ta składa się z sekcji inicjalizacji Arrang, wykonania Act, oraz sprawdzenia warunku Assert.

        [Fact]
        public async void CanGetProblemForDate_20170415()
        {
            //Arrange
            DateTime expected = new DateTime(2017, 04, 15);
            DateTime actual = DateTime.Today;
            IDataService service = new MockDataService();

            //Act
            Problem problem = await service.GetProblemByDateAsync(new DateTime(2017, 04, 15));
            actual = problem.CreationDate;

            //Assert
            Assert.Equal(expected, actual);
        }

Theory

Co w sytuacji kiedy chcemy przetestować kolekcję przypadków testowych? Z pomocą przychodzi nam słówko Theory umożliwia ono nam dostarczenie parametrów wejściowych dla metody testowej.

Przykład użycia możecie zobaczyć na listingu poniżej.

        [Theory]
        [InlineData("2017-04-15")]
        [InlineData("2017-04-16")]
        [InlineData("2017-04-17")]
        public async void CanGetDifferentProblemsForEachDayWhichIsNotNull(DateTime currentDate)
        {
            //Arrange
            IDataService service = new MockDataService();

            //Act
            Problem problem = await service.GetProblemByDateAsync(currentDate);

            //Assert
            Assert.NotNull(problem);
        }

Jeżeli jest nam potrzebny bardziej zaawansowany sposób użycia Theory w którym przekazujemy nasz obiekt jako parametr wejściowy możemy użyć do tego klasy TheoryData.

Przykład użycia na poniższym listingu testuje nam dodawanie kolejnych TodoItem do naszej warstwy serwisu.

    public class DataServiceTests
    {
        private static TodoItem[] todoItems = new TodoItem[]
        {
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a milk", Done = false, DueDate = null},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a TV", Done = false, DueDate = null},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a new iPhone", Done = false, DueDate = DateTime.Today},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a pomodoro", Done = false, DueDate = null},
            new TodoItem { Id = Guid.NewGuid(), Name = "Buy a bread", Done = false, DueDate = null}
        };

        public static TodoTheoryData<TodoItem> TodoItemsData { get; } = new TodoTheoryData<TodoItem>(todoItems);

        [Theory]
        [MemberData("TodoItemsData")]
        public async void InStorageAreFiveItems(TodoItem item)
        {
            //Arrange
            DataService service = new DataService();
            await service.AddTodoItemAsync(item);

            //Act
            IEnumerable<TodoItem> todoItems = await service.GetAllAsync();

            //Assert
            Assert.Equal(5, todoItems.Count());
        }
    }

    public class TodoTheoryData<T> : TheoryData<T>
    {
        public TodoTheoryData(IEnumerable<T> data)
        {
            foreach (T t1 in data)
            {
                Add(t1);
            }
        }
    }

Assert

Klasa Assert dostarcza nam implementację różnych metod wykorzystywanych do sprawdzania naszych wyników, oraz np. oczekiwanych wyjątków.

Podsumowanie

Jak widzicie w prosty sposób można testować aplikacje Xamarin.Forms z użyciem xUnit. Kolejny punkt na liście projektu 10Things to dodanie źródła danych offline z wykorzystaniem bazy SQLite lub Realm.

Tutaj pytanie do czytelników, która baza oferuje lepszy mechanizm synchronizacji offline-online.