Как к модульному тесту метод с оператором 'использования'?

Как я могу записать модульный тест на метод, который имеет оператор использования?

Например, позвольте, предполагают, что у меня есть метод Foo.

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

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

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

17
задан Jay Bazuzi 23 December 2009 в 17:14
поделиться

7 ответов

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

public bool Foo()
{
    using (IMyDisposableClass client = _myDisposableClassFactory.Create())
    {
        return client.SomeOtherMethod();
    }
}
20
ответ дан 30 November 2019 в 11:12
поделиться

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

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

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

0
ответ дан 30 November 2019 в 11:12
поделиться

Без спецификации для Foo, как сказать, как ее протестировать?

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

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

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

.
-1
ответ дан 30 November 2019 в 11:12
поделиться

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

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

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

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

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

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

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

Например (используя носороговые макеты для имитации 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();
}
17
ответ дан 30 November 2019 в 11:12
поделиться

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

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

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

.
6
ответ дан 30 November 2019 в 11:12
поделиться

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

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

.
2
ответ дан 30 November 2019 в 11:12
поделиться

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

Если вы хотите протестировать метод утилизации MyDisposableClass', чтобы проверить, работает ли он, то это должен быть отдельный юнит-тест, построенный против MyDisposableClass.

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

.
-1
ответ дан 30 November 2019 в 11:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: