C# 我可以为';在方法I';我在测试?

C# 我可以为';在方法I';我在测试?,c#,unit-testing,mocking,moq,C#,Unit Testing,Mocking,Moq,我在ActionMethod中模拟model.IsLoggedIn()时遇到问题,可能是因为我正在该ActionMethod中创建viewmodelLoginViewModel的新实例。这就是为什么mockModel.Setup(x=>x.IsLoggedIn())。返回(true)没有缓存它,因为存在具有该方法的类的新实例 是否有任何方法可以在ActionMethod中模拟model.IsLoggedIn(),并使其返回true?如果无法避免在action方法中创建LoginViewModel

我在
ActionMethod
中模拟
model.IsLoggedIn()
时遇到问题,可能是因为我正在该
ActionMethod
中创建viewmodel
LoginViewModel
的新实例。这就是为什么
mockModel.Setup(x=>x.IsLoggedIn())。返回(true)没有缓存它,因为存在具有该方法的类的新实例


是否有任何方法可以在ActionMethod中模拟
model.IsLoggedIn()
,并使其返回
true

如果无法避免在action方法中创建LoginViewModel的新实例,则引入一个实现该功能的工厂。不惜一切代价避免直接创建任何具体类——这使得单元测试变得不可能

如果action方法使用工厂创建对象,则具体工厂将作为控制器的构造函数参数传递。这需要IoC容器和自定义控制器工厂,将其添加到项目中相对简单


有了这个解决方案,单元测试实际上会模拟工厂,所以模拟工厂会返回模拟LoginViewModel对象(实际上是:实现ILoginViewModel接口的模拟对象)。这是我在所有MVC项目中使用的方法,它在生产代码、单元测试和集成测试中都非常有效。

基于上述评论和研究,最好的方法是使用现有的LoginViewModel,而不是创建它的新实例。以下是ActionResult与Moq合作的重新设计的愿景

public ActionResult Login(LoginViewModel viewModel)
    {
        string returnUrl = (string)TempData["ReturnUrl"];           

        if (ModelState.IsValid)
        {
            LoginViewModel model = new LoginViewModel(repository, viewModel);

            if (model.IsLoggedIn())
            {
                if (String.IsNullOrEmpty(returnUrl)) return RedirectToAction("Index", "Home");
                else return Redirect(returnUrl);
            }
            else
            {
                ModelState.AddModelError("Email", "");
                ModelState.AddModelError("Password", "");
            }
        }

        return View(viewModel);
    }

这确实是问题所在。您创建一个新的
LoginViewModel
对象而不是操作现有对象有什么具体原因吗?总之,没有。您试图模拟一个具体的实现。如果没有注入依赖项,则不能模拟它。您传入的
LoginViewModel
实例不是实际调用的
IsLoggedIn
实例,因此设置不匹配。因为只有TypeMock或Fakes可以帮助您解决问题。通过一些重构,您可以很容易地测试这一点,在控制器中创建受保护的虚拟CreateLoginViewModel
将允许您通过普通模拟工具对其进行操作。或者像Jeroen建议的那样重复使用模型。是的,我也是这么想的!如果不使用现有的LoginView模型,我无法模拟它。谢谢你的好主意!从现在起我也要这么做。
public ActionResult Login(LoginViewModel viewModel)
    {
        string returnUrl = (string)TempData["ReturnUrl"];           

        if (ModelState.IsValid)
        {
            LoginViewModel model = new LoginViewModel(repository, viewModel);

            if (model.IsLoggedIn())
            {
                if (String.IsNullOrEmpty(returnUrl)) return RedirectToAction("Index", "Home");
                else return Redirect(returnUrl);
            }
            else
            {
                ModelState.AddModelError("Email", "");
                ModelState.AddModelError("Password", "");
            }
        }

        return View(viewModel);
    }
public ActionResult Login(LoginViewModel viewModel)
    {
        string returnUrl = (string)TempData["ReturnUrl"];           

        if (ModelState.IsValid)
        {
            if (viewModel.IsLoggedIn(repository))
            {
                if (String.IsNullOrEmpty(returnUrl)) return RedirectToAction("Index", "Home");
                else return Redirect(returnUrl);
            }
            else
            {
                ModelState.AddModelError("Email", "");
                ModelState.AddModelError("Password", "");
            }
        }

        return View(viewModel);
    }