简体   繁体   English

如何在C#中进行单元测试中的MapPath

[英]How to MapPath in a unit test in C#

I want to load an external XML file in a unit test to test some processing code on that XML. 我想在单元测试中加载外部XML文件,以测试该XML上的一些处理代码。 How do I get the path of the file? 如何获取文件的路径?

Usually in a web app I would do: 通常在Web应用程序中我会这样做:

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

But obviously in my unit test I have no reference to Server or HttpContext so how can I map a path so that I don't have to specify the full path? 但显然在我的单元测试中我没有引用Server或HttpContext,所以如何映射路径以便我不必指定完整路径?

UPDATE: 更新:

I just want to make it clear that the code I'm actually testing is for an XML parser class, something like: 我只想说明我实际测试的代码是针对XML解析器类的,类似于:

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

So to test this I need to parse a valid XDocument. 所以为了测试这个,我需要解析一个有效的XDocument。 The method being tested does not access the file system itself. 正在测试的方法不会访问文件系统本身。 I could create the XDocument from a String directly in the test code but I thought it would be easier to just load it from a file. 我可以直接在测试代码中从String创建XDocument,但我认为从文件加载它会更容易。

Another idea would be to utilize dependency injection. 另一个想法是利用依赖注入。

public interface IPathMapper {
string MapPath(string relativePath);
}

And then simply use 2 implementations 然后简单地使用2个实现

public class ServerPathMapper : IPathMapper {
     public string MapPath(string relativePath){
          return HttpContext.Current.Server.MapPath(relativePath);
     }
}

And then you also need your mock implementation 然后你还需要你的模拟实现

public class DummyPathMapper : IPathMapper {
    public string MapPath(string relativePath){
        return "C:/Basedir/" + relativePath;
    }
}

And then all your functions that needs to map path's would simply need to have access to an instance of IPathMapper - in your web app it needs to be the ServerPathMapper and in your unit tests the DummyPathMapper - basic DI (Dependency Injection). 然后你需要映射路径的所有函数只需要访问一个IPathMapper实例 - 在你的web应用程序中它需要是ServerPathMapper,并在你的单元中测试DummyPathMapper - 基本DI(依赖注入)。

Personally, I'd be very wary about having any code that relies on a back-end resource store, be that a file system or a database - you are introducing a dependency into your unit test that is likely to lead to false negatives ie tests failing not because of your specific test code but because the file isn't there or the server is unavailable etc. 就个人而言,我会非常谨慎地拥有依赖于后端资源存储的任何代码,无论是文件系统还是数据库 - 您在单元测试中引入了一个可能导致漏报的依赖项,即测试失败不是因为您的特定测试代码,而是因为文件不存在或服务器不可用等。
See this link for IMO a good definition of what a unit test is and more importantly is not 请参阅此链接,了解IMO对单元测试的详细定义,更重要的是不是

Your unit test should be testing an atomic, well-defined piece of functionality not testing whether a file can load. 您的单元测试应该测试一个原子的,明确定义的功能,而不是测试文件是否可以加载。 One solution is to 'mock' the file load - there are various approaches to this however, I'd personally only mock the interface to the file system your are using and not try and do any full filesystem mocking - here's a good SO post and here's a good SO discussion on file system mocking 一种解决方案是“模拟”文件加载 - 但是有各种方法,但我个人只是模拟你正在使用的文件系统的接口,而不是尝试做任何完整的文件系统模拟 - 这是一个很好的SO帖子和这是关于文件系统模拟一个很好的SO讨论

Hope that helps 希望有所帮助

Usually for unit tests I add the xml files as embedded resources to the project and load them using a method like this: 通常对于单元测试,我将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();
  }
}

Edit: I'm starting from scratch since I guess I interpreted your question the wrong way initially. 编辑:我从头开始,因为我想我最初以错误的方式解释你的问题。

The best way to load an XML file in your unit test for injecting it then to some of your classes is to use the DeploymentItem attribute in MS unit tests. 在单元测试中加载XML文件以便将其注入到某些类中的最佳方法是在MS单元测试中使用DeploymentItem属性。

This will look like the following: 这将如下所示:

[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
}

I didn't test the code now on a debugger, but it should work. 我现在没有在调试器上测试代码,但它应该可以工作。

Edit: Btw, when you use DeploymentItem consider this post here . 编辑:顺便说一下,当你使用DeploymentItem时,请在这里考虑这篇文章。

Classes: 类别:

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 */
    }
}

Usage: 用法:

[TestMethod]
public void TestMethod()
{
    var context = new FakeHttpContext();
    string pathToFile = context.Request.MapPath("~/static/all.js");
}

This may be helpful to someone. 这可能对某人有帮助。 I had a related issue. 我有一个相关的问题。 Wanted to use an Excel file from a root-level folder within my c# Unit Test project. 想在我的c#Unit Test项目中使用根级文件夹中的Excel文件。

I had a root-leve folder named "TestFiles". 我有一个名为“TestFiles”的root-leve文件夹。 Inside I had "Test.xlsx". 在里面,我有“Test.xlsx”。

What i did was: 我做的是:

Right-click on the "Test.xlsx", go to Properties and set "Copy To Output Directory" = "Copy Always" 右键单击“Test.xlsx”,转到“属性”并设置“复制到输出目录”=“始终复制”

Now the file and its containing folder "TestFiles" always get copied into the bin folder of the Unit Test project. 现在,文件及其包含文件夹“TestFiles”总是被复制到Unit Test项目的bin文件夹中。 So that I was able to use it like so: 所以我能够像这样使用它:

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();
...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM