Как MapPath в модульном тесте в C#
Я хочу загрузить внешний XML-файл в модульном тесте, чтобы протестировать некоторый код обработки этого XML. Как мне получить путь к файлу?
Обычно в веб-приложении я бы делал:
XDocument.Load(Server.MapPath("/myFile.xml"));
Но очевидно, что в моем модульном тесте у меня нет ссылок на Server или HttpContext, так как я могу сопоставить путь, чтобы мне не пришлось указывать полный путь?
ОБНОВИТЬ:
Я просто хочу прояснить, что код, который я на самом деле тестирую, предназначен для класса XML-анализатора, что-то вроде:
public static class CustomerXmlParser {
public static Customer ParseXml(XDocument xdoc) {
//...
}
}
Поэтому, чтобы проверить это, мне нужно проанализировать действительный XDocument. Тестируемый метод не имеет доступа к самой файловой системе. Я мог создать XDocument из String непосредственно в тестовом коде, но я думал, что будет проще просто загрузить его из файла.
6 ответов
Другая идея заключается в использовании внедрения зависимости.
public interface IPathMapper {
string MapPath(string relativePath);
}
А потом просто использовать 2 реализации
public class ServerPathMapper : IPathMapper {
public string MapPath(string relativePath){
return HttpContext.Current.Server.MapPath(relativePath);
}
}
И тогда вам также нужна ваша фиктивная реализация
public class DummyPathMapper : IPathMapper {
public string MapPath(string relativePath){
return "C:/Basedir/" + relativePath;
}
}
И тогда все ваши функции, которым нужно сопоставить пути, просто должны иметь доступ к экземпляру IPathMapper - в вашем веб-приложении это должен быть ServerPathMapper, а в вашем модуле тестируется DummyPathMapper - базовый DI (Dependency Injection).
Лично я бы очень осторожно относился к любому коду, который опирается на внутреннее хранилище ресурсов, будь то файловая система или база данных - вы вводите зависимость в свой модульный тест, который может привести к ложным отрицаниям, то есть к тестам сбой не из-за вашего конкретного тестового кода, а из-за того, что файл отсутствует или сервер недоступен и т. д.
Посмотрите эту ссылку для ИМО, чтобы получить хорошее определение того, что такое юнит-тест, а главное - нет
Ваш модульный тест должен тестировать элементарный, четко определенный функционал, а не тестировать, может ли файл загружаться. Одно из решений состоит в том, чтобы "смоделировать" загрузку файла - однако существуют различные подходы к этому, однако, я бы лично смоделировал только интерфейс с используемой вами файловой системой, а не пытался делать полную насмешку над файловой системой - вот хороший пост SO и вот хорошее ТАК обсуждение насмешек над файловой системой
надеюсь, это поможет
Обычно для модульных тестов я добавляю XML-файлы в качестве встроенных ресурсов в проект и загружаю их, используя метод, подобный следующему:
public static string LoadResource(string name)
{
Type thisType = MethodBase.GetCurrentMethod().DeclaringType;
string fullName = thisType.Namespace + "." + name + ".xml";
using (Stream stream = thisType.Module.Assembly.GetManifestResourceStream(fullName))
{
if(stream==null)
{
throw new ArgumentException("Resource "+name+" not found.");
}
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
}
Изменить: я начинаю с нуля, так как я думаю, что я неправильно истолковал ваш вопрос.
Лучший способ загрузить XML-файл в модульном тесте для последующего внедрения его в некоторые из ваших классов - это использовать атрибут DeploymentItem в модульных тестах MS.
Это будет выглядеть следующим образом:
[TestMethod]
[DeploymentItem(@"DataXmlFiles\MyTestFile.xml", "DataFiles")]
public void LoadXMLFileTest()
{
//instead of "object" use your returning type (i.e. string, XDocument or whatever)
//LoadXmlFile could be a method in the unit test that actually loads an XML file from the File system
object myLoadedFile = LoadXmlFile(Path.Combine(TestContext.TestDeploymentDir, "DataFiles\\MyTestFile.xml"));
//do some unit test assertions to verify the outcome
}
Я не тестировал код сейчас на отладчике, но он должен работать.
Редактировать: Кстати, когда вы используете DeploymentItem рассмотреть этот пост здесь.
Классы:
internal class FakeHttpContext : HttpContextBase
{
public override HttpRequestBase Request { get { return new FakeHttpRequest(); } }
}
internal class FakeHttpRequest : HttpRequestBase
{
public override string MapPath(string virtualPath)
{
return /* your mock */
}
}
Использование:
[TestMethod]
public void TestMethod()
{
var context = new FakeHttpContext();
string pathToFile = context.Request.MapPath("~/static/all.js");
}
Это может быть полезно для кого-то. У меня была связанная проблема. Хотел использовать файл Excel из папки корневого уровня в моем проекте C# Unit Test.
У меня была корневая папка с именем "TestFiles". Внутри у меня был "Test.xlsx".
То, что я сделал, было:
Щелкните правой кнопкой мыши файл "Test.xlsx", перейдите в "Свойства" и установите "Копировать в выходной каталог" = "Копировать всегда"
Теперь файл и содержащая его папка "TestFiles" всегда копируются в папку bin проекта Unit Test. Так что я смог использовать это так:
var filePath = "TestFiles/Test.xlsx";
var strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=\"Excel 12.0;HDR=Yes;IMEX=0\"";
using (var conn = new OleDbConnection(strConn))
{
conn.Open();
...
}