不使用Moq框架如何Mock HttpFileCollection?可使用NSubstitute
解决方案
方案1:优先适配抽象类(推荐)
HttpFileCollection是密封类且无公开构造函数,但.NET 框架提供了专门为单元测试可Mock设计的抽象基类HttpFileCollectionBase,你可以先修改业务代码的参数类型:
// 修改后的方法签名 uploadFiles(HttpFileCollectionBase files) { for(int i=0;i<files.Count; i++) storeFile(files[i].FileName) }
线上运行时你可以用HttpFileCollectionWrapper把实际的HttpFileCollection实例包一层传入即可,单元测试时直接MockHttpFileCollectionBase即可,以Moq框架为例:
// 单元测试代码示例 var mockFile1 = new Mock<HttpPostedFileBase>(); mockFile1.Setup(f => f.FileName).Returns("test1.txt"); var mockFile2 = new Mock<HttpPostedFileBase>(); mockFile2.Setup(f => f.FileName).Returns("test2.txt"); var mockFiles = new Mock<HttpFileCollectionBase>(); mockFiles.Setup(f => f.Count).Returns(2); mockFiles.Setup(f => f[0]).Returns(mockFile1.Object); mockFiles.Setup(f => f[1]).Returns(mockFile2.Object); // 调用测试方法 uploadFiles(mockFiles.Object);
方案2:无侵入式反射创建实例(不改业务代码)
如果业务代码不允许修改参数类型,可以通过反射调用HttpFileCollection的内部构造函数创建实例,同时构造对应的HttpPostedFile实例:
// 反射构造HttpPostedFile实例 var file1Content = Encoding.UTF8.GetBytes("测试文件内容"); var file1 = (HttpPostedFile)Activator.CreateInstance( typeof(HttpPostedFile), BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { "test1.txt", "text/plain", new MemoryStream(file1Content) }, null); // 反射构造HttpFileCollection实例 var files = (HttpFileCollection)Activator.CreateInstance( typeof(HttpFileCollection), BindingFlags.Instance | BindingFlags.NonPublic, null, null, null); // 把文件添加到集合 files.AddFile("test1.txt", file1); // 调用测试方法 uploadFiles(files);
注意:该方法依赖.NET内部私有API,不同版本的框架可能存在API变更导致测试失效的风险,优先推荐方案1。
内容的提问来源于stack exchange,提问作者user17191981
相关产品推荐
相关产品推荐

