Подтвердить что ты не робот

Как unit test метод с оператором `using`?

Как написать unit test для метода, который имеет инструкцию using?

Например, допустим, что у меня есть метод Foo.

public bool Foo()
{
    using (IMyDisposableClass client = new MyDisposableClass())
    {
        return client.SomeOtherMethod();
    }
}

Как я могу проверить что-то вроде кода выше?

Иногда я предпочитаю не использовать оператор using и Dispose() объект вручную. Я надеюсь, что кто-то покажет мне трюк, который я могу использовать.

4b9b3361

Ответ 1

Если вы построите IMyDisposableClass с помощью factory (введенного в родительский класс) вместо использования нового ключевого слова, вы можете издеваться над IMyDisposable и выполнить проверку на вызов метода dispose.

Ответ 2

Если у вас уже есть свой код и вы спрашиваете, как его проверить, вы сначала не пишете свои тесты... так что на самом деле не делаете TDD.

Однако, у вас здесь есть зависимость. Таким образом, подход TDD должен был бы использовать Injection Dependency. Это можно сделать проще с помощью контейнера IoC, например Unity.

Когда TDD "правильно", ваши мыслительные процессы должны выполняться следующим образом в таком сценарии:

  • Мне нужно сделать Foo
  • Для этого я буду полагаться на внешнюю зависимость, которая будет реализовывать интерфейс (новый или уже существующий) IMyDisposableClass
  • Поэтому я буду вводить IMyDisposableClass в класс, в котором Foo объявляется через свой конструктор

Затем вы должны написать один (или несколько) тестов, которые не выполняются, и только тогда вы оказались бы в том месте, где вы пишете тело функции Foo, и определите, нужно ли вам использовать блок using.

В действительности вы вполне можете знать, что да, вы будете использовать блок using. Но часть точки TDD заключается в том, что вам не нужно беспокоиться об этом, пока не доказали (через тесты), что вам нужно использовать объект, который требует этого.

После того, как вы определили, что вам нужно использовать блок using, вы захотите записать неудавшийся тест, например, используя что-то вроде Rhino Mocks, чтобы установить, что Dispose будет вызван на макет объекта, который реализует IMyDisposableClass.

Например (используя Rhino Mocks для mock IMyDisposableClass).

[TestFixture]
public class When_calling_Foo
{
    [Test]
    public void Should_call_Dispose()
    {
        IMyDisposableClass disposable = MockRepository
                                        .GenerateMock<IMyDisposableClass>();

        Stuff stuff = new Stuff(disposable);

        stuff.Foo();

        disposable.AssertWasCalled(x => x.Dispose());
    }
}

Класс, в котором существует ваша функция Foo, с IMyDisposableClass, введенным как зависимость:

public class Stuff
{
    private readonly IMyDisposableClass _client;

    public Stuff(IMyDisposableClass client)
    {
        _client = client;
    }

    public bool Foo()
    {
        using (_client)
        {
            return _client.SomeOtherMethod();
        }
    }
}

И интерфейс IMyDisposableClass

public interface IMyDisposableClass : IDisposable
{
    bool SomeOtherMethod();
}

Ответ 3

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

Теперь, если ваш вопрос заключается в том, как unit test вышеуказанный фрагмент кода, то этот еще один вопрос полностью, и я думаю, что другие плакаты там ответили.

Иногда я думаю, что есть более сложные слова, чем разработчики:)

Ответ 4

Методы Wrapper, подобные этому, не проверяются на единицу, поскольку вы не можете указать соответствующие предварительные условия или пост-условия.

Чтобы сделать этот метод пригодным для тестирования, вам нужно передать экземпляр IMyDisposableClass в метод или в класс хостинга Foo (и сделать сам класс хоста реализующим IDisposable), чтобы вы могли использовать тест double вместо реальной вещи для проверки любых взаимодействий с ним.

Ответ 5

Ваш вопрос не имеет смысла. Если вы делаете TDD, то метод, который вы опубликовали, уже полностью протестирован, в противном случае он вообще не может существовать. Итак, ваш вопрос не имеет смысла.

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

В TDD просто невозможно, чтобы непроверенный код существовал. Период.

Ответ 6

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

Если вы хотите протестировать метод MyDisposableClass 'dispose, чтобы убедиться, что он работает, это должен быть отдельный unit test, построенный против MyDisposableClass.

Вам не нужно unit test блок using { }, так как это часть языка. Вы либо верите, что он работает, либо не используете С#.:) Я не вижу необходимости писать unit test для подтверждения вызова Dispose().

Ответ 7

Без спецификации Foo, как мы можем сказать, как ее проверить?

  • Получить спецификацию для Foo.
  • Запишите тесты, чтобы убедиться, что они соответствуют всем спецификациям и требованиям (или для разумных подмножеств некоторых функций может потребоваться практически бесконечное количество данных для тестирования).

Я считаю, что у вас есть второй, неявный вопрос, - вот как проверить правильность использования вашего MyDisposableClass. Выделяет объект, когда он освобождается, выходя из условия использования. Это отдельная тестовая проблема и не должна сочетаться с тестом Foo, поскольку спецификация Foo не должна ссылаться на конкретные данные конкретной реализации, такие как использование вашего MyDisposabeClass.

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