Как написать модульные тесты в стиле контекста / спецификации с помощью инфраструктуры MSTest / xUnit? - PullRequest
22 голосов
/ 13 января 2011

Я использую MSpec для написания своих модульных тестов и действительно предпочитаю стиль BDD, я думаю, что он намного более читабелен.Сейчас я использую Silverlight, который MSpec не поддерживает, поэтому мне нужно использовать MSTest, но я все еще хотел бы поддерживать стиль BDD, поэтому я пытаюсь найти способ сделать это.

Просто чтобы объяснитьто, что я пытаюсь достичь, вот как я написал бы тест MSpec

[Subject(typeof(Calculator))]    
public class when_I_add_two_numbers : with_calculator
{
  Establish context = () => this.Calculator = new Calculator();
  Because I_add_2_and_4 = () => this.Calculator.Add(2).Add(4);
  It should_display_6 = () => this.Calculator.Result.ShouldEqual(6);
}

public class with_calculator
{
  protected static Calculator;
}

Так что с MSTest я бы попытался написать тест следующим образом (хотя вы можете видеть, что он не будет работать, потому что явставил 2 атрибута TestInitialize, но вы получаете то, что я пытаюсь сделать ..)

[TestClass]
public class when_I_add_two_numbers : with_calculator
{
   [TestInitialize]
   public void GivenIHaveACalculator()
   {
      this.Calculator = new Calculator();
   }

   [TestInitialize]
   public void WhenIAdd2And4()
   {
      this.Calculator.Add(2).Add(4);
   }

   [TestMethod]
   public void ThenItShouldDisplay6()
   {
      this.Calculator.Result.ShouldEqual(6);
   }
}

public class with_calculator
{
  protected Calculator Calculator {get;set;}
}

Может кто-нибудь придумать несколько более изящных предложений по написанию тестов таким способом с помощью MSTest?

Ответы [ 5 ]

34 голосов
/ 13 января 2011

Что вы думаете об этом:

[TestClass]
public class when_i_add_two_numbers : with_calculator
{
    public override void When()
    {
        this.calc.Add(2, 4);
    }

    [TestMethod]
    public void ThenItShouldDisplay6()
    {
        Assert.AreEqual(6, this.calc.Result);
    }

    [TestMethod]
    public void ThenTheCalculatorShouldNotBeNull()
    {
        Assert.IsNotNull(this.calc);
    }
}

public abstract class with_calculator : SpecificationContext
{
    protected Calculator calc;

    public override void Given()
    {
        this.calc = new Calculator();
    }
}

public abstract class SpecificationContext
{
    [TestInitialize]
    public void Init()
    {
        this.Given();
        this.When();
    }

    public virtual void Given(){}
    public virtual void When(){}
}

public class Calculator
{
    public int Result { get; private set; }
    public void Add(int p, int p_2)
    {
        this.Result = p + p_2;
    }
}
2 голосов
/ 03 августа 2012

У Марка Нейхофа есть пример выполнения тестирования стиля «дано когда было» с NUnit в его репозитории Fohjin.DDD github .

Вот выдержка из приведенного выше примера:

public class When_registering_an_domain_event : BaseTestFixture<PreProcessor>
{
    /* ... */

    protected override void When()
    {
        SubjectUnderTest.RegisterForPreProcessing<ClientMovedEvent>();
        SubjectUnderTest.Process();
    }

    [Then]
    public void Then_the_event_processors_for_client_moved_event_will_be_registered()
    {
        IEnumerable<EventProcessor> eventProcessors;
        EventProcessorCache.TryGetEventProcessorsFor(typeof(ClientMovedEvent), out eventProcessors);
        eventProcessors.Count().WillBe(1);
    }
}

И вы можете увидеть данное в реализации базового класса :

[Given]
public void Setup()
{
    CaughtException = new NoExceptionWasThrownException();
    Given();

    try
    {
        When();
    }
    catch (Exception exception)
    {
        CaughtException = exception;
    }
    finally
    {
        Finally();
    }
}
1 голос
/ 10 апреля 2013

Я задавал подобные вопросы много, хотя в последнее время.Есть много разумных вариантов, и вы можете легко создать свой собственный, как показано в некоторых ответах в этом посте.Я работал над средой тестирования BDD с целью облегчить ее распространение на любую среду модульного тестирования.В настоящее время я поддерживаю MSTest и NUnit.Его называют , учитывая , и это с открытым исходным кодом.Основная идея довольно проста, поскольку Given предоставляет оболочки для общих наборов функциональных возможностей, которые затем можно реализовать для каждого участника теста.

Ниже приведен пример теста NUnit Given:

[Story(AsA = "car manufacturer",
       IWant = "a factory that makes the right cars",
       SoThat = "I can make money")]
public class when_building_a_toyota : Specification
{
    static CarFactory _factory;
    static Car _car;

    given a_car_factory = () =>
                              {
                                  _factory = new CarFactory();
                              };

    when building_a_toyota = () => _car = _factory.Make(CarType.Toyota);

    [then]
    public void it_should_create_a_car()
    {
        _car.ShouldNotBeNull();
    }

    [then]
    public void it_should_be_the_right_type_of_car()
    {
        _car.Type.ShouldEqual(CarType.Toyota);
    }
}

Я старался изо всех сил, чтобы оставаться верным понятиям из блога Дэна Норта «Вводящий BDD », и поэтому все делается с использованием заданного, когда и тогда стиля спецификации.То, как это реализовано, позволяет вам иметь несколько данных и даже несколько когда, и они должны выполняться по порядку (все еще проверяя это).

Кроме того, имеется полный набор расширений If, включенных непосредственно в Given.Это разрешает такие вещи, как вызов ShouldEqual(), показанный выше, но полон хороших методов для сравнения коллекций, сравнения типов и т. Д. Для тех из вас, кто знаком с MSpec, я в основном разорвал их и сделал некоторые модификации, чтобы они работали внеMSpec.

Окупаемость, однако, я думаю, в отчетности.Бегущий по тестам заполнен созданным вами сценарием, так что сразу вы можете получить подробную информацию о том, что фактически делает каждый тест, не углубляясь в код: Test Runner

Кроме того, HTML-отчетсоздан с использованием шаблонов t4 на основе результатов тестов для каждой сборки.Классы с соответствующими историями все вложены вместе, и имя каждого сценария напечатано для быстрого ознакомления.Для приведенных выше тестов отчет будет выглядеть следующим образом: Report Example

Неудачные тесты будут окрашены в красный цвет и их можно будет щелкнуть, чтобы просмотреть подробности исключения.

Вот и все.Я использую его в нескольких проектах, над которыми я работаю, поэтому он все еще активно разрабатывается, но я бы назвал ядро ​​довольно стабильным.Я ищу способ разделять контексты по составу, а не по наследству, так что это, вероятно, будет одним из следующих изменений, которые появятся в будущем.Ввести на критику.:)

0 голосов
/ 05 марта 2018

MSTestEnhancer может помочь вам, и вы можете получить пакет через NuGet.org .


Вот пример кода:

[TestClass]
public class TheTestedClassTest
{
    [ContractTestCase]
    public void TheTestedMethod()
    {
        "When Xxx happens, results in Yyy.".Test(() =>
        {
            // Write test case code here...
        });

        "When Zzz happens, results in Www.".Test(() =>
        {
            // Write test case code here...
        });
    }
}

И когда вы увидите свой результат теста, вы получите это ниже:

Test results

Я написал пост, чтобы представить больше информацииоб этом.См. Представление MSTestEnhancer для удобства чтения результатов модульного теста - walterlv для получения более подробной информации.

0 голосов
/ 12 марта 2015

Вы можете использовать NUnit.Specifications и писать тесты, подобные этому:

using NUnit.Specifications;
using Should;

public class OrderSpecs
{
    [Component]
    public class when_a_customer_places_an_order : ContextSpecification
    {
        static OrderService _orderService;
        static bool _results;
        static Order _order;

        Establish context = () =>
        {
            _orderService = new OrderService();
            _order = new Order();
        };

        Because of = () => _results = _orderService.PlaceOrder(_order);

        It should_successfully_place_the_order = () => _results.ShouldBeTrue();
    }
}
...