【问题标题】:Unit testing controller with dependency injected service and repository具有依赖注入服务和存储库的单元测试控制器
【发布时间】:2012-03-14 21:11:40
【问题描述】:

我有一个非常标准的 .NET MVC 3 应用程序,它使用 Ninject 进行依赖注入。我试图单元测试的是从控制器返回的视图。有一个控制器,上面有一个组服务,该服务有一个存储库。该服务首先检查该组是否存在,如果存在,它会返回 false 以及错误。控制器然后检查布尔值以确定是将用户移动到组列表还是停留在当前页面并显示一个值。

控制器

[HttpPost]
public ActionResult AddGroup(Group g)
{
   string error = string.Empty;
   if (groupService.Save(g, CurrentUser, out error))
   {
       return RedirectToAction("GetGroups");
   }
   else
   {
       ViewData["Error"] = error;
       return View("AddGroup");
   }
}

服务

[Inject]
public IGroupRepository CurrentGroupRepo { get; set; }

public bool Save(Group group, string username, out string error)
{
    error = string.Empty;
    var found = CurrentGroupRepo.GetGroup(group.Descr, false);
    if (found != null)
    {
        error = "That group alread exists";
        return false;
    }

    if (group.CreatedBy == null || group.CreatedBy == string.Empty)
    {
        group.CreatedBy = username;
        group.CreatedOn = DateTime.Now;
        group.IsDeleted =false;
    }

    group.ModifiedBy = username;
    group.ModifiedOn = DateTime.Now;

    try
    {
        if (group.GroupID == 0)
        {
            CurrentGroupRepo.AddGroup(group);
        }
        else
        {
            CurrentGroupRepo.UpdateGroup(group);
        }
        return true;
    }
    catch (Exception ex)
    {
        error = ex.Message + ex.StackTrace;
        return false;
    }
}

单元测试

[TestMethod]
public void TestAddGroup()
{
    // Arrange
    Mock<IUserService> uService = new Mock<IUserService>();
    Mock<IGroupService> gService = new Mock<IGroupService>();
    Mock<IObservationService> oService = new Mock<IObservationService>();
    Mock<IGroupRepository> mockGroupRepo = new Mock<IGroupRepository>();

        string error = string.Empty;
        List<Group> groups = new List<Group>();
        Group newGroup = new Group() { Descr = "Test Group 1234566", IsDeleted = false };
        Mock<IGroupRepository> mockGroupRepo = new Mock<IGroupRepository>();

        mockGroupRepo.Setup(cr => cr.GetGroups(It.IsAny<bool>())).Returns(
            delegate {
                return groups;
            });
        mockGroupRepo.Setup(cr => cr.GetGroup(It.IsAny<string>(), It.IsAny<bool>())).Returns(
            delegate(Group _group) {
                return groups.Where(f => f.Descr == _group.Descr).FirstOrDefault();
            });
        mockGroupRepo.Setup(cr => cr.AddGroup(newGroup)).Returns(
            delegate {
                groups.Add(newGroup);
                return newGroup;
            });
        gService.SetupGet(d => d.CurrentGroupRepo).Returns(mockGroupRepo.Object);


    AdminController controller = new AdminController(gService.Object, uService.Object, oService.Object);
    Group newGroup = new Group() { Descr = "Test Group 1234566", IsDeleted = false };
    var success = (ViewResult)controller.AddGroup(newGroup);
    Assert.IsTrue("GetGroups" == success.ViewName);

    var failure = (ViewResult)controller.AddGroup(newGroup);
    Assert.IsTrue("AddGroup" == failure.ViewName);
}

我要测试的是,当我添加一个组时,它应该可以工作,然后当我添加同一个组时,它应该转到不同的视图。但是现在,单元测试使用的是真实的存储库而不是模拟的存储库。如何让模拟服务上的存储库由单元测试控制,而不是实际使用真实的存储库?

【问题讨论】:

    标签: unit-testing ninject moq


    【解决方案1】:

    如果您正在对控制器进行单元测试,那么您无需担心存储库,因为您的服务是模拟的。就控制器而言,没有存储库,它只知道 IGroupService 合约。

    鉴于您提供的代码,我无法看到您的睾丸如何使用真实的存储库。如果您想更改测试的结果,您需要为您的 IGroupService 模拟提供一些模拟响应。

    您需要对采用 Mocked Repository 的 GroupService 进行第二次单元测试。

    IMO 单元测试应该只测试一个类,其他一切 应该被模拟或者是非常简单的 dto 对象。如果你是 做更多的事情就是集成测试。

    【讨论】:

    • 我一定遗漏了一些非常简单的东西,因为它一直保存到数据库而不是单元测试中的集合。我已经更新了测试以显示我手动设置存储库并将其放置在模拟服务上,但代表永远不会被调用。我是否必须创建一个从 NinjectModule 注入的 DefaultModule 并创建新的绑定到模拟以进行单元测试?
    • @Josh 我不是 ninject 专家。我使用温莎,但概念应该是相同的。据我所知,由于控制器不使用存储库,因此无需模拟存储库。事实上,您的 IoC 甚至不应该与单元测试级别相关。您是否显示了从单元测试线开始的所有内容,是否有没有显示的设置?
    • 您的回答最终为我指明了正确的方向。我会跟进。
    【解决方案2】:

    根据 Bronumski 的建议,我最终将其简化了一些。这是代码,一切似乎又运行良好了。

            [TestMethod]
        public void TestAddGroup() {
            // Arrange
            Group newGroup = new Group() { Descr = "Test Group 1234566", IsDeleted = false };
            gService.Setup(cr => cr.Save(It.IsAny<Group>(), It.IsAny<string>())).Returns("");
    
            AdminController controller = new AdminController(gService.Object, uService.Object, oService.Object);
    
            // Act 
            var success = (RedirectToRouteResult)controller.AddGroup(newGroup);
            Assert.IsTrue("GetGroups" == success.RouteValues["action"].ToString());
    
            gService.Setup(cr => cr.Save(It.IsAny<Group>(), It.IsAny<string>())).Returns("Error");
            var failure = (ViewResult)controller.AddGroup(newGroup);
            Assert.IsTrue("AddGroup" == failure.ViewName);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 2013-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-20
      相关资源
      最近更新 更多