10

据我所知,答案是否定的。我看到的问题来自System.Web.Optimization.Bundle类中的Include(params string[])方法。这在内部调用System.Web.Optimization.IncludeDirectory(string, string, bool),这反过来又使用此代码:是否有可能在MVC4中对BundleConfig进行单元测试?

DirectoryInfo directoryInfo = new DirectoryInfo(
    HttpContext.Current.Server.MapPath(directoryVirtualPath)); 

虽然有可能一个单元测试过程中设置HttpContext.Current,我无法弄清楚如何使其.Server.MapPath(string directoryVirtualPath)返回一个非空字符串。由于DirectoryInfo(string)构造函数在传递null参数时引发异常,因此此类测试总是失败。

.NET团队对此的建议是什么?作为集成测试或用户验收测试的一部分,我们是否必须单元测试捆绑配置?

+4

真的吗?我将不得不在这个上开始赏金? – danludwig 2012-07-11 12:07:20

回答

9

我对你有一些好消息,对于RTM我们增加了对BundleTable一个新的静态属性,以使更多的单元测试:

public static Func<string, string> MapPathMethod; 

编辑更新与测试虚拟路径提供:

所以你可以这样做:

public class TestVirtualPathProvider : VirtualPathProvider { 

    private string NormalizeVirtualPath(string virtualPath, bool isDirectory = false) { 
     if (!virtualPath.StartsWith("~")) { 
      virtualPath = "~" + virtualPath; 
     } 
     virtualPath = virtualPath.Replace('\\', '/'); 
     // Normalize directories to always have an ending "/" 
     if (isDirectory && !virtualPath.EndsWith("/")) { 
      return virtualPath + "/"; 
     } 
     return virtualPath; 
    } 

    // Files on disk (virtualPath -> file) 
    private Dictionary<string, VirtualFile> _fileMap = new Dictionary<string, VirtualFile>(); 
    private Dictionary<string, VirtualFile> FileMap { 
     get { return _fileMap; } 
    } 

    public void AddFile(VirtualFile file) { 
     FileMap[NormalizeVirtualPath(file.VirtualPath)] = file; 
    } 

    private Dictionary<string, VirtualDirectory> _directoryMap = new Dictionary<string, VirtualDirectory>(); 
    private Dictionary<string, VirtualDirectory> DirectoryMap { 
     get { return _directoryMap; } 
    } 

    public void AddDirectory(VirtualDirectory dir) { 
     DirectoryMap[NormalizeVirtualPath(dir.VirtualPath, isDirectory: true)] = dir; 
    } 

    public override bool FileExists(string virtualPath) { 
     return FileMap.ContainsKey(NormalizeVirtualPath(virtualPath)); 
    } 

    public override bool DirectoryExists(string virtualDir) { 
     return DirectoryMap.ContainsKey(NormalizeVirtualPath(virtualDir, isDirectory: true)); 
    } 

    public override VirtualFile GetFile(string virtualPath) { 
     return FileMap[NormalizeVirtualPath(virtualPath)]; 
    } 

    public override VirtualDirectory GetDirectory(string virtualDir) { 
     return DirectoryMap[NormalizeVirtualPath(virtualDir, isDirectory: true)]; 
    } 

    internal class TestVirtualFile : VirtualFile { 
     public TestVirtualFile(string virtualPath, string contents) 
      : base(virtualPath) { 
      Contents = contents; 
     } 

     public string Contents { get; set; } 

     public override Stream Open() { 
      return new MemoryStream(UTF8Encoding.Default.GetBytes(Contents)); 
     } 
    } 

    internal class TestVirtualDirectory : VirtualDirectory { 
     public TestVirtualDirectory(string virtualPath) 
      : base(virtualPath) { 
     } 

     public List<VirtualFile> _directoryFiles = new List<VirtualFile>(); 
     public List<VirtualFile> DirectoryFiles { 
      get { 
       return _directoryFiles; 
      } 
     } 

     public List<VirtualDirectory> _subDirs = new List<VirtualDirectory>(); 
     public List<VirtualDirectory> SubDirectories { 
      get { 
       return _subDirs; 
      } 
     } 

     public override IEnumerable Files { 
      get { 
       return DirectoryFiles; 
      } 
     } 

     public override IEnumerable Children { 
      get { throw new NotImplementedException(); } 
     } 

     public override IEnumerable Directories { 
      get { 
       return SubDirectories; 
      } 
     } 
    } 

然后用这样的单元测试编写:

[TestMethod] 
    public void StyleBundleCustomVPPIncludeVersionSelectsTest() { 
     //Setup the vpp to contain the files/directories 
     TestVirtualPathProvider vpp = new TestVirtualPathProvider(); 
     var directory = new TestVirtualPathProvider.TestVirtualDirectory("/dir/"); 
     directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style1.0.css", "correct")); 
     directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style.css", "wrong")); 
     vpp.AddDirectory(directory); 

     // Setup the bundle 
     ScriptBundle bundle = new ScriptBundle("~/bundles/test"); 
     bundle.Items.VirtualPathProvider = vpp; 
     bundle.Include("~/dir/style{version}.css"); 

     // Verify the bundle repsonse 
     BundleContext context = SetupContext(bundle, vpp); 
     BundleResponse response = bundle.GetBundleResponse(context); 
     Assert.AreEqual(@"correct", response.Content); 
    } 
+1

不幸的是,由于MapPathMethod已被删除,所以在最新版本中不再可能使用此解决方法。你可以建议一个替代策略(可能使用VirtualPathProvider)吗? – 2013-08-03 13:55:42

+1

当然增加了我用于单元测试的测试vpp – 2013-08-08 03:07:30

+0

看起来它再次改变了,bundle中没有Item属性了。 – Giedrius 2013-08-13 13:43:19

5

在.Net 4.5中有一些变化。这是已更新的已批准答案的工作版本以适应这些更改(我正在使用Autofac)。注意“GenerateBundleResponse”而不是“GetBundleResponse”:

[Fact] 
    public void StyleBundleIncludesVersion() 
    { 
     //Setup the vpp to contain the files/directories 
     var vpp = new TestVirtualPathProvider(); 
     var directory = new TestVirtualPathProvider.TestVirtualDirectory("/dir/"); 
     directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style1.0.css", "correct")); 
     directory.DirectoryFiles.Add(new TestVirtualPathProvider.TestVirtualFile("/dir/style.css", "wrong")); 
     vpp.AddDirectory(directory); 

     // Setup the bundle 
     var bundleCollection = new BundleCollection(); 
     var bundle = new ScriptBundle("~/bundles/test"); 
     BundleTable.VirtualPathProvider = vpp; 
     bundle.Include("~/dir/style{version}.css"); 
     bundleCollection.Add(bundle); 
     var mockHttpContext = new Mock<HttpContextBase>(); 

     // Verify the bundle repsonse 
     var context = new BundleContext(mockHttpContext.Object, bundleCollection, vpp.ToString()); 
     var response = bundle.GenerateBundleResponse(context); 
     Assert.Equal(@"correct", response.Content); 
    } 
相关问题