单元测试文件上传失败

时间:2014-07-18 15:51:05

标签: asp.net-mvc unit-testing

我有一个在数据库中插入文件的操作。它工作正常。但是插入成功时单元测试失败。 RedirectToRouteResult为null。这是操作的代码:

[HttpPost] public ActionResult FileUpload(FileUploadViewModel model) { try { if (ModelState.IsValid) { var uploadFile = new byte[model.File.InputStream.Length]; model.File.InputStream.Read(uploadFile, 0, uploadFile.Length); //var file = new FilesUpload(); var fileExt = Path.GetExtension(model.File.FileName); if (fileExt == ".txt" || fileExt == ".docx") { //file.FileName = model.File.FileName; //file.FileSize = model.File.ContentLength; //file.ContentType = fileExt; //file.FileData = uploadFile; //file.UploadedOn = DateTime.Now; //var user = _userRepository.GetUserId(User.Identity.Name); //file.UserId = user.UserId; bool result = _userRepository.UploadFile(model, User.Identity.Name, fileExt, uploadFile); //file.User = (from u in _context.Users where u.UserId == 29 select u).FirstOrDefault(); //_context.FilesUploads.Add(file); //int result = _context.SaveChanges(); if (result) { return RedirectToAction("Index"); } else { ModelState.AddModelError("", "An error occured"); return View(model); } } else { ModelState.AddModelError("", "You can upload only files with extensions .txt and .docx"); } } return View(model); } catch (Exception ex) { throw(ex); } }

这是单元测试的代码:

    private SuperUserController _controller;
    private Mock<IUserRepository> _repositoryMock;
    private Mock<IIntrinsicObjects> _intrinsicMock;
    private Mock<ControllerContext> _contextMock;
    private string username = "test@abv.bg";
    private FileUploadViewModel _fileUpload;

    [SetUp]
    public void Setup()
    {
        _fileUpload = new FileUploadViewModel();
        _repositoryMock = new Mock<IUserRepository>();
        _intrinsicMock = new Mock<IIntrinsicObjects>();
        _contextMock = new Mock<ControllerContext>();
        _contextMock.SetupGet(c => c.HttpContext.User.Identity.Name).Returns(username);
        _contextMock.SetupGet(c => c.HttpContext.User.Identity.IsAuthenticated).Returns(true);
        _controller = new SuperUserController(_repositoryMock.Object, _intrinsicMock.Object);
        _controller.ControllerContext = _contextMock.Object;
    }


[Test]
    public void FileUpload_ShouldRedirectToIndexOnSuccess()
    {
        string filePath = Path.GetFullPath(@"C:\Users\Test\Desktop\test.txt");
        var fileStream = new FileStream(filePath, FileMode.Open);
        var fileExt = Path.GetExtension(filePath);
        var fileToUpload = new Mock<HttpPostedFileBase>();
        fileToUpload.Setup(f => f.ContentLength).Returns(10);
        fileToUpload.Setup(f => f.FileName).Returns("test.txt");
        fileToUpload.Setup(f => f.ContentType).Returns(fileExt);
        fileToUpload.Setup(f => f.InputStream).Returns(fileStream);
        //var model = new FileUploadViewModel();
        _fileUpload.File = fileToUpload.Object;
        var fileData = new byte[fileToUpload.Object.InputStream.Length];
        _repositoryMock.Setup(m => m.UploadFile(_fileUpload, _controller.ControllerContext.HttpContext.User.Identity.Name, fileToUpload.Object.ContentType, fileData)).Returns(true);
        var result = _controller.FileUpload(_fileUpload) as RedirectToRouteResult;
        Assert.IsNotNull(result);
    }

问题是UploadFile总是返回false。

如果有人帮助我,我将非常感激。

2 个答案:

答案 0 :(得分:1)

您的控制器操作会创建一个包含文件数据的新数组:

var uploadFile = new byte[model.File.InputStream.Length];

这永远不会与您fileData的{​​{1}}上设置的UploadFile参数相匹配:

_repositoryMock

默认情况下,数组将通过引用匹配,而不是内容相同。在控制器创建新实例时,_repositoryMock.Setup(m => m.UploadFile(_fileUpload, _controller.ControllerContext.HttpContext.User.Identity.Name, fileToUpload.Object.ContentType, fileData)).Returns(true); uploadFile的引用不同。

您希望设置moq,以便在提交预期的数据数组时,您的UploadFile函数返回true。为此,您可以使用匹配可枚举中的所有元素的自定义匹配器:

fileData

使用数据阵列的匹配器设置模拟器:

public T[] MatchCollection<T>(T[] expectation)
{
    //This checks all elements in input are find in destination, regardless of order or duplicates
    return Match.Create<T[]>(inputCollection => (expectation.All((i) => inputCollection.Contains(i))));

    //This will check the arrays are exactly the same
    return Match.Create<T[]>(inputCollection =>  StructuralComparisons.StructuralEqualityComparer.Equals(inputCollection, expectation) );
}

希望它有所帮助!

修改


我已根据您的代码尝试使用以下测试,该代码将有效的数组数据传递给模拟设置,而不需要在单元测试中实际读取文件:

_repositoryMock.Setup(m => m.UploadFile(_fileUpload, _controller.ControllerContext.HttpContext.User.Identity.Name, fileToUpload.Object.ContentType, MatchCollection(fileData))).Returns(true);

答案 1 :(得分:0)

这是测试的最终版本:

[Test]
    public void FileUpload_ShouldRedirectToIndexOnSuccess()
    {
        string filePath = Path.GetFullPath(@"C:\Users\Yordanka\Desktop\test.txt");
        var fileStream = new FileStream(filePath, FileMode.Open);
        var fileExt = Path.GetExtension(filePath);
        var testarray = new byte[414];
        var fileToUpload = new Mock<HttpPostedFileBase>();
        fileToUpload.Setup(f => f.ContentLength).Returns(414);
        fileToUpload.Setup(f => f.FileName).Returns("test.txt");
        fileToUpload.Setup(f => f.ContentType).Returns(fileExt);
        fileToUpload.Setup(f => f.InputStream).Returns(fileStream);
        fileToUpload.Setup(f => f.InputStream.Length).Returns(testarray.Length);
        _fileUpload.File = fileToUpload.Object;
        var fileData = new byte[414];
        _fileUpload.File.InputStream.Read(fileData, 0, fileData.Length);
        _repositoryMock.Setup(
            m =>
                m.UploadFile(_fileUpload, _controller.ControllerContext.HttpContext.User.Identity.Name,
                    fileToUpload.Object.ContentType, MatchCollection(fileData))).Returns(true);
        var result = _controller.FileUpload(_fileUpload) as RedirectToRouteResult;
        Assert.IsNotNull(result);
        Assert.AreEqual("Index", result.RouteValues["Action"]);
        Assert.AreEqual("SuperUser", result.RouteValues["Controller"]);

    }

再次感谢Daniel J.G !!!!