【问题标题】:Unit testing a MVC controller对 MVC 控制器进行单元测试
【发布时间】:2013-12-08 06:47:01
【问题描述】:

我正在尝试找出为 MVC 应用程序构建单元测试的最佳方法。我创建了一个简单的模型和接口,供控制器构造函数使用,以便测试框架 (Nsubstitute) 可以传递存储库的模拟版本。该测试按预期通过。

我的问题是现在我想更进一步,在 IHomeRepository 的“真实”实例中测试文件 I/O 操作。此实现应该从 App_Data 目录中的文件中读取一个值。

我尝试在不传递 IHomeRepsotory 的模拟版本的情况下构建测试,但是当我运行测试时 HttpContext.Current 为空。

我需要模拟 HttpContext 吗?我是否以正确的方式处理这件事?

//The model
public class VersionModel
{
    public String BuildNumber { get; set; }
}



//Interface defining the repository
public interface IHomeRepository
{
    VersionModel Version { get; }
}


//define the controller so the unit testing framework can pass in a mocked reposiotry.  The default constructor creates a real repository
public class HomeController : Controller
{

    public IHomeRepository HomeRepository;

    public HomeController()
    {
        HomeRepository = new HomeRepoRepository();
    }

    public HomeController(IHomeRepository homeRepository)
    {
        HomeRepository = homeRepository;
    }
.
.
.

}


class HomeRepoRepository : IHomeRepository
{
    private VersionModel _version;

    VersionModel IHomeRepository.Version
    {
        get
        {
            if (_version == null)
            {
                var absoluteFileLocation = HttpContext.Current.Server.MapPath("~/App_Data/repo.txt");
                if (absoluteFileLocation != null)
                {           
                    _version = new VersionModel() //read the values from file (not shown here)
                    {
                        BuildNumber = "value from file",
                    };
                }
                else
                {
                    throw new Exception("path is null");
                }
            }
            return _version;
        }
    }
}



[Fact]
public void Version()
{
    // Arrange
    var repo = Substitute.For<IHomeRepository>();  //using Nsubstitute, but could be any mock framework
    repo.Version.Returns(new VersionModel
    {
       BuildNumber = "1.2.3.4",
    });

    HomeController controller = new HomeController(repo);  //pass in the mocked repository

    // Act
    ViewResult result = controller.Version() as ViewResult;
    var m = (VersionModel)result.Model;

    // Assert
    Assert.True(!string.IsNullOrEmpty(m.Changeset));
}

【问题讨论】:

    标签: asp.net-mvc unit-testing mocking


    【解决方案1】:

    我相信您想测试连接到真实数据库的 IHomeRepository 的真实实例。在这种情况下,您需要一个App.config file, which specify the connection string。这不是单元测试,而是集成测试。在 HttpContext 为空的情况下,您仍然 can fake the HttpContext,从数据库中检索真实数据。另见here

    【讨论】:

    • 我最初的问题是正确读取文件。我最好将该代码放在带有文件路径参数的单独类中,然后对该类进行单元测试?
    • 这取决于你如何阅读文件。比如你读文件的时候有什么逻辑。如果它不是微不足道的,是的,正是你所说的。将代码放在一个单独的类中,并将该操作作为集成测试。所以你不必担心HttpContext。如果您的文件足够简单,我不会担心将其放入单独的类中并对其进行测试。在这种情况下,您的单元测试就足够了。
    • 您认为这种方法会更好吗? stackoverflow.com/questions/8740498/…
    • 是的,如果您正在编写单元测试,这是一个明智的示例。
    猜你喜欢
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 2011-08-12
    • 2012-05-25
    • 2011-12-01
    • 1970-01-01
    • 2017-06-02
    相关资源
    最近更新 更多