Рекомендации по нескольким утверждениям по одному и тому же результату в С#

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

[TestFixture]
public class GridControllerTests
{
    protected readonly string RequestedViewId = "A1";

    protected GridViewModel Result { get; set;}

    [TestFixtureSetUp]
    public void Get_UsingStaticSettings_Assign()
    {
        var dataRepository = new XmlRepository("test.xml");

        var settingsRepository = new StaticViewSettingsRepository();

        var controller = new GridController(dataRepository, settingsRepository);

        this.Result = controller.Get(RequestedViewId);

    }

    [Test]
    public void Get_UsingStaticSettings_NotNull()
    {
        Assert.That(this.Result,Is.Not.Null);
    }

    [Test]
    public void Get_UsingStaticSettings_HasData()
    {
        Assert.That(this.Result.Data,Is.Not.Null);
        Assert.That(this.Result.Data.Count,Is.GreaterThan(0));
    }

    [Test]
    public void Get_UsingStaticSettings_IdMatches()
    {
        Assert.That(this.Result.State.ViewId,Is.EqualTo(RequestedViewId));
    }

    [Test]
    public void Get_UsingStaticSettings_FirstTimePageIsOne()
    {
        Assert.That(this.Result.State.CurrentPage, Is.EqualTo(1));
    }
}

Ответ 1

Наличие нескольких утверждений в одном и том же тесте может привести к Assertion Roulette, так что это то, о чем вы всегда должны быть осторожны.

Однако, Assertion Roulette в основном является проблемой, когда утверждения не связаны. Если они концептуально тесно связаны, многие утверждения часто можно рассматривать как единые логические утверждения.

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

Ответ 2

То, что вам нужно сохранить, - это шаблон Упорядочить, Закон, Утвердить (и затем закончить тест). В вашем случае все расположение находится в TestFixtureSetUp, как и проверяемое действие. Я бы немного перестроил это, это может стать громоздким, когда у вас будет больше тестов. Как отмечает Dockers, следует избегать тяжелых тестовых установок, они могут стать проблемой - они "подходят для всех" для всех тестов в классе и поэтому могут стать тяжелее, чем требуется большинству тестов.

Если у вас возникает соблазн продолжить другое действие, а затем больше утверждений, поставьте это в отдельном тесте.

У меня нет проблем с размещением нескольких утверждений в одном и том же тесте, если они способствуют тестированию одной и той же вещи (т.е. являются частью одного и того же "логического утверждения" ). В этом случае любое количество утверждений о содержимом этого файла .Result.Data было бы в порядке, я бы просмотрел одно и то же значение результата. Ваш Get_UsingStaticSettings_HasData делает это очень четко. Лучше всего использовать уникальное сообщение об ошибке для каждого утверждения, чтобы было легче определить, какое утверждение не удалось.

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

В резюме
 * Сделайте одно действие за тест
 * После действия используйте как можно больше связанных утверждений, так как вам нужно протестировать одну вещь
 * Завершите тест.

Ответ 3

Вы можете использовать Oapt - NUnit Addin для запуска одного теста на тест:

[TestFixture]
public class GridControllerTests
{
  [TestCase, ForEachAssert]
  public void Get_UsingStaticSettings_Assign()
  {
      var dataRepository = new XmlRepository("test.xml");
      var settingsRepository = new StaticViewSettingsRepository();
      var controller = new GridController(dataRepository, settingsRepository);

      var result = controller.Get("A1");

      AssertOne.From(
        () => Assert.That(this.Result,Is.Not.Null),
        () => Assert.That(this.Result.Data,Is.Not.Null),
        () => Assert.That(this.Result.Data.Count,Is.GreaterThan(0)),
        () => Assert.That(this.Result.State.ViewId,Is.EqualTo(RequestedViewId)),
        () => Assert.That(this.Result.State.CurrentPage, Is.EqualTo(1)));
  }
}

Это создаст 5 различных тестовых примеров, по одному для каждого утверждения.

Ответ 4

Я склонен ставить утверждения самостоятельно, только если они ценны сами по себе. Если я хочу получить утверждение самостоятельно, я создаю собственное утверждение:

AssertThatMyObjectMatches(field1, field2, field3, field4, myObject);

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

Assert.True(list.IsEmpty());

list.Add(new Thing());
Assert.False(list.IsEmpty());

Другие, включая большую часть сообщества Ruby, имеют другое мнение по этому поводу. В основном это связано с сообщением Дейва Астелса, здесь:

http://www.artima.com/weblogs/viewpost.jsp?thread=35578

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

Что бы ни работало для вас и вашей команды, это, вероятно, правильный путь. Я, как правило, делаю все, что кажется простым и легким в изменении, чтобы быть верным позже, когда у меня есть лучшее представление о том, что правильно. Я также добавляю много комментариев Given / When / Then на уровне единицы в более сложных примерах и разбиваю класс, если он становится слишком сложным для понимания.

Причиной написания тестов таким способом является не то, что вы можете ловить вещи, которые ломаются. Это поможет людям понять код и изменить его, не нарушая при этом вещей в первую очередь.