Есть некоторые вещи, которые вы просто не можете проверить? - PullRequest
2 голосов
/ 05 августа 2009

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

Если у нас есть класс, который напрямую зависит от .NET Framework, то есть класса System.IO.File, то мы не сможем проверить это в отдельности.

Конечно, мы можем обернуть его и внедрить в зависимый класс, но затем мы начнем оборачивать каждый класс .NET! Что, если эта обертка не прямой вызов? Возможно, сначала нужно выполнить проверку / бизнес-логику, которую вы хотите протестировать?

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

Вот пример на C #, чтобы проиллюстрировать мою точку зрения:

Этот класс тесно связан с .NET Framework ... это нормально, но сейчас я не могу проверить его изолированно, для этого требуются файлы и т. Д.

public class PathResolver
{
    public string Resolve(string filename)
    {
        string completePath = string.Empty;
        if(!File.Exists(filename))
        {
            return Path.Combine(@"D:\MyExample", filename);
        }
        return completePath;
    }
}

Мы можем протестировать это, выполнив что-то вроде:

public class PathResolver
{
    private readonly IFileSystem _fileSystem;

    public PathResolver(IFileSystem fileSystem)
    {
        _fileSystem = fileSystem;
    }

    public string Resolve(string filename)
    {
        string completePath = string.Empty;
        if(!_fileSystem.Exists(filename))
        {
            return _fileSystem.Combine(@"D:\MyExample", filename);
        }
        return completePath;
    }
}

Но теперь мы не можем протестировать класс FileSystem!

Что думают другие люди?

Ответы [ 9 ]

5 голосов
/ 05 августа 2009

В целом, тестирование фреймворков, таких как .NET, не ваша ответственность, а ответственность людей, выпускающих фреймворк.

1 голос
/ 05 августа 2009

Это прекрасный пример различия между модульным тестированием и интеграционным тестированием. Для модульного тестирования вашего PathResolver вам необходимо передать фиктивный объект, созданный вручную или с использованием фиктивного фреймворка (например, моего любимого Moq ). Используя фиктивный объект, вы сможете проверить, был ли вызван метод Combine.

Модульный тест будет выглядеть примерно так (с использованием Moq):

[Test]
public void ShouldCombinePath()
{
    IFileSystem fs = new Mock<IFileSystem>();

    PathResolver resolver = new PathResolver(fs.Object);

    resolver.Resolve("Test.filename");

    fs.Verify(fs => fs.Combine());
}

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

Но вы правы, вам все равно нужно проверить конкретный класс. Это то, что мы называем интеграционным тестированием . Я предлагаю вам создать отдельный проект под названием «MyProject.IntegrationTest» и протестировать SystemFileSystem напрямую, используя тестовые файлы, включенные в проект.

Интеграционный тест должен выглядеть следующим образом

[Test]
public void ShouldCombinePath()
{
    DotNetFileSystem fileSystem = new DotNetFileSystem();

    string resultPath = fileSystem.Combine("Test.filename");

    Assert.That(resultPath, Text.Contains("@D:\MyExample\Test.filename"));
}

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

1 голос
/ 05 августа 2009

Действительно, в какой-то момент вам придется реализовать интерфейсы, подобные IFileSystem, тем самым приклеив ваше приложение к .NET Framework. Этот «промежуточный код» не может быть проверен модулем. Это не большая проблема, если склеенный код очень прост.

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

Причина, по которой юнит-тесты более популярны, заключается в том, что их проще создавать и они менее хрупки. Вам не нужно готовить базу данных, веб-сервер или файловую систему для запуска модульного теста. Вам не нужно беспокоиться о модульных тестах для взлома класса A, если вы измените класс B. Интеграционные тесты могут проверить больше вещей, но у них нет этих преимуществ.

1 голос
/ 05 августа 2009

Нет необходимости заглушать ваши зависимости от всего фреймворка - только те части, которые затрудняют вашу возможность модульного тестирования вашего кода. Так что я думаю, что вы можете не стеснять операции System.IO.File вместе с вызовами базы данных. Я также нахожу очень полезным иметь интерфейс IClock, чтобы сообщать время вместо вызова DateTime.UtcNow - это позволяет нам контролировать течение времени в модульных тестах.

0 голосов
/ 05 августа 2009

Если вы не можете протестировать класс, но можете смоделировать его с помощью Isolation Framework (Rhino Mocks, Typemock, Moq), вы можете подделать детали этого «непроверяемого» класса.

0 голосов
/ 05 августа 2009

Вам нужно только проверить свой класс, а не рамки ниже.

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

Хороший тестдрайвер также очищает тестовый сценарий и оставляет систему в том же состоянии, что и до теста.

0 голосов
/ 05 августа 2009

К сожалению, вы не можете проверить все в приложении при модульном тестировании. Вот почему при тестировании вы стремитесь к тому, чтобы ваши тесты охватывали 90% кода по проекту.

Сделайте этот тест как часть вашего интеграционного тестирования или даже части вашего комплексного тестирования, потому что действие по тестированию будет довольно дорогим

0 голосов
/ 05 августа 2009

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

0 голосов
/ 05 августа 2009

Хотите протестировать System.IO? Если нет, то почему бы не использовать подход насмешки / заглушки, чтобы избавиться от зависимости?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...