Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 7387 сообщений
Cообщения с меткой

библиотеки - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Сверхлегкая BDD: малая механизация автономных тестов

Понедельник, 26 Сентября 2016 г. 08:17 (ссылка)

Тема автономного тестирования давняя, почтенная, разобранная до косточек.

Кажется, что после отличной книги Роя Ошероува и сказать особо нечего.

Но на мой взгляд есть некоторая несбалансированность доступных инструментов.

С одной стороны монстры вроде SpecFlow, с огромным оверхедом ради возможности писать тесты-спецификации на квази-естественном языке, с другой — челябинская суровость фреймворков старой школы вроде NUnit.

Чего не хватает? Инструмента для лаконичной, выразительной, легко читаемой записи тестов, по удобству и ортогональности аналогичного библиотекам для создания подделок, таких как FakeItEasy, или проверки утверждений вроде FluentAssertion.





В настоящий момент я пытаюсь создать такой инструмент.



BDD из топора



Вот так выглядит типичный тест с использованием моей микробиблиотеки:



[Test]
public void GivenSelfUsableWhenDisposeThenValueShouldBeDisposed()
{
Given(A.Fake().ToUsable()).
When(_ => _.Dispose()).
Then(_ => _.Value.ShouldBeDisposed());
}


Также задействованы библиотеки FakeItEasy и FluentAssertions, но не как зависимости, а каждая для решения своих задач (подделки и проверка утверждений).

Эквивалентный код в стиле старой школы:



[Test]
public void GivenSelfUsableWhenDisposeThenValueShouldBeDisposed()
{
// Arrange
var usable = A.Fake().ToUsable();

// Act
usable.Dispose();

// Assert
usable.Value.ShouldBeDisposed();
}


Поддержка моков



Но это еще не все.

Допустим, у нас есть мок — подделка, для которой после выполнения тестового сценария мы делаем проверку утверждений. По Ошероуву таких должно быть не больше одного на тест.

Код в новом стиле:



[Test]
public void GivenNeutralUsableWhenDisposeThenValueShouldBeNotDisposed()
{
Given(A.Fake()).
And(mock => mock.ToNeutralUsable()).
When(_ => _.Dispose()).
ThenMock(_ => _.ShouldBeNotDisposed());
}


С помощью метода And результат предыдущего Given фиксируется как мок, а тестовым объектом становится результат работы делегата. Это логично, так как мок используется в тестируемом объекте и его естественно создавать раньше.

Часто утверждения включают в себя и мок, и тестируемый объект. Такой вариант тоже поддерживается:



[Test]
public void GivenObjectWhenToUsableThenValueShouldBeSameAsObject()
{
Given(A.Fake()).
And(mock => mock.ToUsable(A.Dummy())).
When(_ => _).
Then((_, mock) => _.Value.Should().Be.SameAs(mock));
}


Поддержка исключений



Очень часто тест, в котором проверяемое утверждение включает выброс исключения выглядит очень громоздко и нечитаемо на фоне "чистых" вариантов. Новый подход позволяет проверять исключения и лаконично, и стилистически единообразно с "гладкими" тестами.



[Test]
public void GivenDisposableWhenDisposeTwiceThenShouldBeDisposedTwice()
{
Given(A.Fake()).
And(mock => A.Dummy().ToUsable(mock)).
When(_ => _.Dispose()).
And(_ => _.Dispose()).
ThenCatch(e => e.Should().Be.OfType());
}


Кроме того, в этом коде видна...



Поддержка дополнительных действий и утверждений.



С помощью метода расширения And можно добавить дополнительные действия и проверки утверждений (выполняются в порядке записи вызовов метода). Это позволяет удобно структурировать код тестов.



Секретный ингредиент



Топором в микробиблиотеке работает вот такой класс:



public abstract class GivenWhenThenBase
{
internal GivenWhenThenBase(T result, TMock mock)
{
Result = result;
Mock = mock;
}

internal T Result { get; set; }
internal TMock Mock { get; }
}


Отдельным этапам тестирования соответствуют его наследники



public sealed class GivenResult : GivenWhenThenBase
{
internal GivenResult(T result, TMock mock) : base(result, mock) {}
}

public sealed class WhenResult : GivenWhenThenBase
{
internal WhenResult(T result, TMock mock, Exception e = null) : base(result, mock)
{
Exception = e;
}

internal Exception Exception { get; set; }
}

public sealed class ThenResult : GivenWhenThenBase
{
internal ThenResult(T result, TMock mock, Exception e = null) : base(result, mock)
{
Exception = e;
}

internal Exception Exception { get; set; }
}


Наследование реализации спроектировано в соответствии с рекомендациями из моей предыдущей статьи.



Приправы



Вся видимая магия реализована в LINQ-стиле с помощью обобщенных методов расширения.




  1. Создание теcтируемого объекта (и мока)

    public static GivenResult Given(T result) => 
    new GivenResult(result, null);


    public static GivenResult And(this GivenResult givenResult, Func and) => 
    new GivenResult(and(givenResult.Result), givenResult.Result);

  2. Прогон тестового сценария

    public static WhenResult When(this GivenResult givenResult, Func when)
    {
    try
    {
    return new WhenResult(when(givenResult.Result), givenResult.Mock);
    }
    catch (Exception e)
    {
    return new WhenResult(default(TResult), givenResult.Mock, e);
    }
    }


    public static WhenResult And(this WhenResult whenResult, Func and)
    {
    if (whenResult.Exception != null)
    return new WhenResult(default(TResult), whenResult.Mock, whenResult.Exception);
    try
    {
    return new WhenResult(and(whenResult.Result, whenResult.Mock), whenResult.Mock);
    }
    catch (Exception e)
    {
    return new WhenResult(default(TResult), whenResult.Mock, e);
    }
    }


    public static WhenResult When(this GivenResult givenResult, Action when)
    {
    return givenResult.When(o =>
    {
    when(o);
    return o;
    });
    }


    public static WhenResult And(this WhenResult whenResult, Action and)
    {
    return whenResult.And((o, m) =>
    {
    and(o, m);
    return o;
    });
    }

  3. Проверка утверждений:

    public static ThenResult Then(this WhenResult whenResult, Action then)
    {
    then(whenResult.Result, whenResult.Mock, whenResult.Exception);
    return new ThenResult(whenResult.Result, whenResult.Mock, whenResult.Exception);
    }


    public static ThenResult Then(this WhenResult whenResult, Action then)
    {
    return whenResult.Then((r, m, e) =>
    {
    e.Should().Be.Null();
    then(r, m);
    });
    }


    public static ThenResult ThenMock(this WhenResult whenResult, Action then)
    {
    return whenResult.Then((r, m, e) =>
    {
    e.Should().Be.Null();
    then(m);
    });
    }


    public static ThenResult Then(this WhenResult whenResult, Action then)
    {
    return whenResult.Then((r, m, e) =>
    {
    e.Should().Be.Null();
    then(r, m);
    });
    }


    public static ThenResult ThenCatch(this WhenResult whenResult, Action then)
    {
    return whenResult.Then((r, m, e) =>
    {
    e.Should().Not.Be.Null();
    then(e);
    });
    }



Подопытный кролик



В примерах кода испытаниям на прочность подвергался класс из моей статьи Disposable без границ и несколько методов расширения. На данный момент класс переименован из Disposable в Usable во избежании коллизий имен с повсеместно используемым паттерном.



public sealed class Usable : IDisposable
{
internal Usable(T resource, IDisposable usageTime)
{
_usageTime = usageTime;
Value = resource;
}

public void Dispose() => _usageTime.Dispose();

public T Value { get; }

private readonly IDisposable _usageTime;
}


public static class UsableExtensions
{
public static Usable ToUsable(this T resource, IDisposable usageTime) =>
new Usable(resource, usageTime);

public static Usable ToUsable(this T resource) where T : IDisposable =>
resource.ToUsable(resource);

public static Usable ToNeutralUsable(this T resource) =>
resource.ToUsable(Disposable.Empty);
}


Итоги



Плюшки нового подхода по сравнению со старой школой:




  1. Код вместо комментариев

  2. То, что понимает и контролирует компилятор, приближено к тому что понимает и контролирует человек.

  3. Лучше и лаконичность, и выразительность, и читаемость.

  4. Повторяющиеся действия выделяются в отдельные методы легко и приятно.

  5. В едином стиле с обычными тестами поддержано использование моков и утверждений для выброшенных исключений



Плюшки по сравнению с высокоуровневыми BDD-фреймворками:




  1. В разы меньше церемоний и многословия.

  2. Ортогональность по отношению к другим библиотекам, облегчающим тестирование.

  3. Язык тестов — обычный C#, поддержанный всей мощью студии и армией разработчиков.



Дополнения и критика традиционно приветствуются.


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/310942/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Татьяна_Болтунова

5 ЛЕГАЛЬНЫХ ОНЛАЙН-БИБЛИОТЕК, НА КОТОРЫХ МОЖНО ЧИТАТЬ И СКАЧИВАТЬ КНИГИ БЕСПЛАТНО.

Среда, 14 Сентября 2016 г. 19:35 (ссылка)

Это цитата сообщения оксяня Оригинальное сообщение

5 легальных онлайн-библиотек, на которых можно читать и скачивать книги бесплатно.




5 легальных онлайн-библиотек, на которых можно читать и скачивать книги бесплатно.



 






Ссылка на сайт




 



Читать далее...
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
-_Снежана_-

Удивительно красиво...

Воскресенье, 11 Сентября 2016 г. 13:11 (ссылка)

Library of the Abbey in Waldsassen, Bavaria. - Библиотека аббатства в Вальдзассен, Бавария.

3338d187aad4952c8debbc88371c0194 (564x535, 86Kb)

more
Метки:   Комментарии (3)КомментироватьВ цитатник или сообщество

Следующие 30  »

<библиотеки - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda