2017-09-14 67 views
1

我是单元测试新手。我想测试的东西很简单:验证File.Delete与Moq调用

[HttpPost] 
public ActionResult EditProfile(ProfileViewModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     // Retrieve current user 
     var userId = User.Identity.GetUserId(); 
     var user = _dataRepository.GetUserById(userId); 

     //If it isn't the single-instance default picture, delete the current profile 
     // picture from the Profile_Pictures folder 
     if (!String.Equals(user.ProfilePictureUrl, _defaultPic)) 
      System.IO.File.Delete(Server.MapPath(user.ProfilePictureUrl)); 

在这部分代码,我创建了一个条件,这条线将评估为真:

if (!String.Equals(user.ProfilePictureUrl, _defaultPic)) 

我想验证System.IO.File.Delete是调用。

这样做的最好方法是什么?

我是否需要通过在我自己的类中包装System.IO.File.Delete调用来实现接口重构,以便我可以嘲笑它并验证它是否被调用?

我正在使用Moq。

+0

你的最后一句话是绝对正确的。用一个可以让你嘲笑它的抽象来封装IO调用。 – Nkosi

+0

谢谢@Nkosi! –

+0

你也应该为'Service.MapPath'做同样的事情那些是可以抽象出来的实现问题。实际上,整个陈述可以被封装在一个抽象中。 – Nkosi

回答

1

我需要通过包裹在自己的班上System.IO.File.Delete呼叫实现一个接口,这样我可以嘲笑它,并验证它被称为重构?

封装的实施涉及

public interface IFileSystem { 
    void Delete(string path); 

    //...code removed for brevity 
} 

public class ServerFileSystemWrapper : IFileSystem { 
    public void Delete(string path) { 
     System.IO.File.Delete(Server.MapPath(path)); 
    } 

    //...code removed for brevity 
} 

这将通过构造函数注入明确注入家属和使用。

if (!String.Equals(user.ProfilePictureUrl, _defaultPic)) 
    _fileSystem.Delete(user.ProfilePictureUrl); //IFileSystem.Delete(string path) 

现在,这将使嘲笑是建立和验证为需要

//Arrange 
var mockFile = new Mock<IFileSystem>(); 

var profilePictureUrl = "..."; 

//...code removed for brevity 

var sut = new AccountController(mockFile.Object, ....); 

//Act 
var result = sut.EditProfile(model); 

//Assert 
result.Should().NotBeNull(); 
mockFile.Verify(_ => _.Delete(profilePictureUrl), Times.AtLeastOnce());