Как unit-test класс, который должен иметь конкретный файл
В настоящее время я пытаюсь изучить правильный unit тест. Итак, теперь я пытаюсь написать unit-тесты для класса, который должен отображать данные из XML файла в соответствующие объекты. Конечно, вся функциональность класса зависит от существования соответствующего XML файла. XML файл загружается в конструктор класса.
Я использую С# с NUnit. Пока у меня два теста:
[Test]
public void ShouldAllowInstanceToBeCreatedWhenXMLFileIsPresent()
{
if (File.Exists(SettingsReader.XML_SETTINGS_PATH))
{
SettingsReader settingsReader = new SettingsReader();
Assert.AreNotEqual(null, settingsReader);
}
}
[Test]
[ExpectedException("Telekanzlei.Clientmanager.XMLDataLayer.XMLFileNotFoundException")]
public void ShouldThrowExceptionWhenXMLFileIsNotPresent()
{
if (!File.Exists(SettingsReader.XML_SETTINGS_PATH))
{
SettingsReader settingsReader = new SettingsReader();
}
else
throw new XMLFileNotFoundException();
}
Я не уверен, что проверка наличия файла в тесте - это правильный способ, поэтому любые предложения по этим тестам тоже приветствуются. Но мой вопрос в том, как продолжить следующие тесты. Очевидно, что все последующие тесты будут терпеть неудачу, если XML файл отсутствует.
Итак, я предполагаю, что XML файл присутствует, имея в виду, что неудачный тест может означать, что это не так? Это мне не показалось бы.
Существует ли общий шаблон для решения такой проблемы?
спасибо для любой помощи
edit: переписал второй тест, так как он потерпел неудачу, если файл действительно присутствовал...
edit2: Может ли это помочь вам рассказать, что на самом деле делает SettingsReader. Пока это выглядит так:
public class SettingsReader
{
public static readonly string XML_SETTINGS_PATH = "C:\\Telekanzlei\\Clientmanager_2.0\\Settings.xml";
public XElement RootXElement { get; private set; }
public SettingsReader()
{
if (!File.Exists(XML_SETTINGS_PATH))
throw new XMLFileNotFoundException();
using (var fs = File.OpenRead(XML_SETTINGS_PATH))
{
RootXElement = XElement.Load(fs);
}
}
}
Я не уверен, но я думаю, что StreamReader не был бы здесь, не так ли?
Ответы
Ответ 1
Проблема не в ваших модульных тестах, а в дизайне класса. Я бы предложил рефакторинг класса, чтобы он не открывал файл, а вместо этого работал с потоком. Тогда ваши модульные тесты могут просто заменить поток файлов для потока памяти - просто!:)
public class SettingsReader()
{
public SettingsReader(System.IO.StreamReader reader)
{
// read contents of stream...
}
}
// In production code:
new SettingsReader(new StreamReader(File.Open("settings.xml")));
// In unit test:
new SettingsReader(new StringReader("<settings>dummy settings</settings>"));
Помните, что открытие файлов и данных настроек синтаксиса - это две очень разные проблемы.
Ответ 2
Если вам нужно предложить использовать метод SetUp для копирования или проверки наличия файла.
Я предлагаю убедиться, что файл присутствует, добавив его в тестовый проект и пометив его как "копировать всегда", как только вы получите эту работу, нет необходимости перепроверять ее.
Если у вас много тестов, требующих внешних файлов, возможно, вы должны использовать MsTest - у него есть атрибут, называемый DeploymentItem, который гарантирует, что файл будет скопирован в то же место, что и тест.
Ответ 3
Рассмотрим переписывание кода, чтобы зависимости могли быть переданы или каким-то другим образом зачеркнуты для кода, который вы хотите провести с помощью модуля.
т.е. передать что-то вроде экземпляра "IMySettingsFileProvider" в конструктор SettingsReader, где IMySettingsFileProvider.SettingsXml возвращает некоторый установочный поток. Таким образом, вы можете обмануть интерфейс IMySettingsFileProvider для теста, а не требовать, чтобы файл присутствовал на диске.
Ответ 4
Один из вариантов заключается в том, чтобы поместить это в верхнюю часть тестового прибора. Тогда тесты будут действительны только тогда, когда файл существует.
[SetUp]
public void Setup()
{
Assume.That(File.Exists(SettingsReader.XML_SETTINGS_PATH));
}