我有一个在数据库中插入文件的操作。它工作正常。但是插入成功时单元测试失败。 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。
如果有人帮助我,我将非常感激。
答案 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 !!!!