Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 测试ASP.NET MVC控制器而不影响数据库的干净方法?_Asp.net Mvc_Unit Testing_Mocking_Rhino Mocks - Fatal编程技术网

Asp.net mvc 测试ASP.NET MVC控制器而不影响数据库的干净方法?

Asp.net mvc 测试ASP.NET MVC控制器而不影响数据库的干净方法?,asp.net-mvc,unit-testing,mocking,rhino-mocks,Asp.net Mvc,Unit Testing,Mocking,Rhino Mocks,我正试图想出一个好办法来清理我的控制器,使它们更易于测试,而不必依赖于一个固定的数据库连接。我想我已经有了一个不错的开始,用IObjectContext抽象出了我的对象上下文。这在上下文中效果很好,但我的下一个问题是,我在整个项目的许多操作方法中都使用了一个新的方法(请参见下面的代码) 除了默认构造函数之外,我的控制器还包含一个重载,它接受IObjectContext(简单依赖项注入)。在我的单元测试中,我可以轻松地模拟IObjectContext。我的问题是在各种操作方法中处理我的通用存储库。

我正试图想出一个好办法来清理我的控制器,使它们更易于测试,而不必依赖于一个固定的数据库连接。我想我已经有了一个不错的开始,用IObjectContext抽象出了我的对象上下文。这在上下文中效果很好,但我的下一个问题是,我在整个项目的许多操作方法中都使用了一个新的方法(请参见下面的代码)

除了默认构造函数之外,我的控制器还包含一个重载,它接受IObjectContext(简单依赖项注入)。在我的单元测试中,我可以轻松地模拟IObjectContext。我的问题是在各种操作方法中处理我的通用存储库。我可以向控制器添加一些额外的构造函数重载,但我担心这会很快变得混乱。然而,如果不这样做,我就无法想出一种干净的方法来提高可测试性,从而不必依赖数据库连接

有没有我忽略的简单解决方案

/// <summary>
/// Initializes a new instance of the HomeController class
/// </summary>
public HomeController(IObjectContext context)
{
    _context = context;
}

/// <summary>
/// GET: /home/index
/// </summary>
/// <returns>Renders the home page</returns>
public ActionResult Index()
{
    List contacts;
    HomeViewModel model;

    using (IRepository<Contact> repository = new DataRepository<Contact>(_context))
    {
        contacts = new List(repository.GetAll());
    }

    model = new HomeViewModel(contacts);

    return View(model);
}
//
///初始化HomeController类的新实例
/// 
公共HomeController(IObjectContext上下文)
{
_上下文=上下文;
}
/// 
///获取:/home/索引
/// 
///呈现主页
公共行动结果索引()
{
列出联系人名单;
HomeViewModel模型;
使用(IRepository repository=新数据存储库(_上下文))
{
联系人=新列表(repository.GetAll());
}
型号=新的HomeViewModel(联系人);
返回视图(模型);
}
如果我不得不添加额外的构造函数重载以适应我的担忧,我正在考虑为操作方法使用的每个存储库的控制器添加一些私有属性(这将在需要之前取消存储库的实例化)。例如:

private IRepository<Contact> _contactRepository;

private IRepository<Contact> ContactRepository
{
    get
    {
        return _contactRepository ?? (_contactRepository = new DataRepository<Contact>());
    }
}
私人IRepository\u contactRepository;
私有IRepository存储库
{
得到
{
返回_contactRepository???(_contactRepository=newdatarepository());
}
}
出于单元测试的目的,我可以使用构造函数重载预先初始化存储库


你对此有何看法?我是否遗漏了一些显而易见的更清晰的东西?

好吧,我一直按照您最后的示例所示,将模拟注入到我的控制器中。它确实有一点味道(为可测试性而设计),但它编码不错,测试效果也不错。

首先,摆脱当前的混蛋注入构造函数重载。对于DI,您应该只需要一个构造函数,而这个构造函数将接受所有依赖项。(要启用ASP.NET MVC运行时来创建控制器,请实现自定义IControllerFactory。)

下一步是通过构造函数注入所有依赖项。当您认为由于构造函数参数太多而变得混乱时,这是一个很好的迹象,表明您违反了。当这种情况发生时,您将提取一个


清洗并重复:)

您对通用存储库的使用与其说是依赖项注入,不如说是一种依赖项掩蔽设备。您应该能够看到特定控制器使用的所有依赖项:通用存储库将这一事实隐藏在控制器内部深处的某个地方,这使得维护(和单元测试)代码变得更加困难。我的建议是:使用具体的存储库


您还可以看看。

您能模拟一下您的存储库吗?谢谢您的回复。这实际上是我的部分观点。我当然可以,但是有没有一种干净的方法来实现我的控制器,这样我就不会因为使用另一个存储库的每个可能的操作方法而导致构造函数过载?例如,一种操作方法依赖于几个不同的存储库。