我如何模拟另一个在控制器动作中调用的方法?

时间:2018-09-03 07:17:02

标签: c# unit-testing tdd

在这里,我有一个场景,出于某种输入目的,我必须在控制器动作中调用另一个函数。 如下。

public IActionResult Dashboard()
        {
            try
            {
                    var allStuds = repository.GetAllStudentss();
                    var result = getFirstClassResult(allStuds);
                    return View("Dashboard", result );                         
            }
            catch (Exception ex)
            {             
                return View();
            }
        }


 public List<DashboardViewModel> getFirstClassResult(List<DashboardViewModel> model)
        {
      return students.OrderByDescending(x=>x.ExamDate).ToList();
    }

这是我的Tets案例中的代码。

var controller = new StudentController(repositoryMock.Object, null, sessionManagerMock.Object);
    var date = new DateTime();
    var model= new List<DashboardViewModel>          
    controller.ControllerContext.HttpContext = GetHttpContext(CreateSessionMock(true), authenticationServiceMock);
    controller.TempData = new TempDataDictionary(controller.ControllerContext.HttpContext, Mock.Of<ITempDataProvider>());
    controller.Url = GetUrlHelper();
    contextMock.Setup(mock => mock.GetAllStudents()).Returns(model);
    var repository = new StudentRepository(factoryMock.Object);
    var res = repository.GetAllStudents();                
    var result = controller.Dashboard() as ViewResult;
    Assert.Equal("Dashboard", result.ViewName);

在这里,我要编写测试用例,其中必须模拟getFirstClassResult(allStuds)方法。 无法做到的。

1 个答案:

答案 0 :(得分:0)

下面的代码行扼杀了一切,并引入了无法在控制器和数据访问层之间建立强耦合的单元测试的可能性:

IUserRepository repo = new UserRepository();

绝对不要在任何应用程序(不仅是ASP.NET MVC)中编写类似这样的内容。如果您编写这样的代码,它将始终在单元测试中失败,并且您将无法对其进行测试。

这不可能模拟/单元测试。

您应该使用构造函数注入来减弱层之间的耦合:

public class UserController : Controller{
private readonly IUserRepository _repos;
public UserController(IUserRepository repo)
{
    _repos = repo;
}

public ActionResult Index()
{
    return RedirectToAction("Details");
}

public ActionResult Details()
{
    IQueryable<Business.Entities.User> users = _repos.GetAll();
    return View("Details", users);
}}

现在您可以通过模拟隔离进行单元测试:

   [Test]
   public void Details()
   {
Mock<IUserRepository> mockRepo = new Mock<IUserRepository>();
mockRepo.Setup(ur => ur.GetAll()).Returns(MockedGetAll());
var v = mockRepo.Object.GetAll();

var controller = new UserController(mockRepo.Object);
var result = controller.List() as ViewResult;
var model = result.ViewData.Model as IQueryable<User>;

Assert.AreEqual("List", result.ViewName);
Assert.IsNotNull(model);
Assert.Greater(model.Count(), 0);}

显然,因为现在您的控制器依赖于此存储库,所以您可以使用DI框架来配置依赖项。

不想使用DI框架的人经常编写这样的代码,并提供2个构造函数(一个用于单元测试,一个用于实际应用程序):

private readonly IUserRepository _repo;
public UserController(IUserRepository repo)
{
_repo = repo;
 }
 public UserController(): this(new UserRepository())
 {}

另请参阅 religion of dependency injection