Как MapPath в unit test в С#

Я хочу загрузить внешний XML файл в unit test, чтобы протестировать некоторый код обработки на этом XML. Как получить путь к файлу?

Обычно в веб-приложении я бы сделал:

XDocument.Load(Server.MapPath("/myFile.xml"));

Но, очевидно, в моем unit test у меня нет ссылки на Server или HttpContext, так как я могу сопоставить путь, чтобы мне не нужно указывать полный путь?

UPDATE:

Я просто хочу дать понять, что код, который я на самом деле тестирую, предназначен для класса парсера XML, например:

public static class CustomerXmlParser {
  public static Customer ParseXml(XDocument xdoc) {
    //...
  }
}

Итак, чтобы проверить это, мне нужно проанализировать действительный XDocument. Тестируемый метод не имеет доступа к самой файловой системе. Я мог бы создать XDocument из String непосредственно в тестовом коде, но я подумал, что было бы проще просто загрузить его из файла.

Ответ 1

Еще одна идея - использовать инъекцию зависимостей.

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, а в вашем модуле тестируется базовый DI (Dependency Injection) DummyPathMapper.

Ответ 2

Лично я бы очень настороженно относился к тому, что любой код, который опирается на внешний хранилище ресурсов, будь то файловая система или база данных - вы вводите зависимость в свой unit test, которая может привести к ложным отрицаниям, т.е. тесты не выполняются не из-за вашего конкретного тестового кода, а из-за того, что файл отсутствует или сервер недоступен и т.д.
См. Ссылку для IMO. Хорошее определение того, что означает unit test, а главное не

Ваш unit test должен тестировать атомную, четко определенную функциональность, не проверяющую, может ли файл загружаться. Одно из решений заключается в том, чтобы "издеваться над файловой нагрузкой", однако есть разные подходы к этому, я лично только издевался над интерфейсом к файловой системе, которую вы используете, а не пытаетесь сделать какую-либо полную файловую систему насмешкой - здесь хорошая публикация SO и здесь хорошая дискуссия SO о файловой системе, насмехающейся

Надеюсь, что поможет

Ответ 3

Обычно для модульных тестов я добавляю файлы 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();
  }
}

Ответ 4

Редактирование: я начинаю с нуля, так как я предполагаю, что изначально я неправильно понял ваш вопрос.

Лучший способ загрузить XML файл в ваш unit test для его инъекции, а затем в некоторые из ваших классов - использовать атрибут 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
}

Я не тестировал код сейчас в отладчике, но он должен работать.

Edit: Кстати, когда вы используете DeploymentItem, рассмотрите этот пост здесь.

Ответ 5

Классы:

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");
}