首页 > 解决方案 > 如何在单元测试控制器 moq 上下文中跳过调用函数?

问题描述

这是我的控制器

BusinessLayer.Lookup.Lookup_Rooms RoomsBL = new BusinessLayer.Lookup.Lookup_Rooms();

[HttpPost]
public ActionResult CreateRoom(UMIS_Portal_BackEnd.Areas.StudentAcadimic.Models.RoomLocationModel room) {
        
    if (ModelState.IsValid)
    {
        try
        {
            // TODO: Add insert logic here

           

           
            int? Serial = RoomsBL.Lookup_RoomInsert(room.BuildingFloorID, room.RoomName, room.Min_Capacity, room.Max_Capacity);
           
        }
        catch (Exception error)
        {
            
            ViewBag.Messages = error.InnerException.Message;
         
        }

    }
    return View();
}

我只想测试此操作结果是否存在视图,因此我编写了此代码

[TestMethod()]
public void CreateRoomTestPost()
{
    LookupRoomsController controller = new LookupRoomsController();
  
    UMIS_Portal_BackEnd.Areas.StudentAcadimic.Models.RoomLocationModel room = new UMIS_Portal_BackEnd.Areas.StudentAcadimic.Models.RoomLocationModel();

    ViewResult viewResult = controller.CreateRoom(room) as ViewResult;
    Assert.IsNotNull(viewResult);
 
}

我希望测试跳过调用

int? Serial = RoomsBL.Lookup_RoomInsert(room.BuildingFloorID, room.RoomName, room.Min_Capacity, room.Max_Capacity); 

在主控制器动作上。

标签: c#asp.net-mvcunit-testingmoq

解决方案


问题是控制器与实现细节紧密耦合

BusinessLayer.Lookup.Lookup_Rooms RoomsBL = new BusinessLayer.Lookup.Lookup_Rooms();

而不是将抽象显式注入其中。创建其依赖关系不是控制器的责任。(单一职责原则 (SRP) 和关注点分离 (Soc))

Lookup_Rooms 需要抽象

public interface ILookup_Rooms {
    //...
}

public class Lookup_Rooms : ILookup_Rooms {
    //...
}

并将抽象显式注入控制器。

private readonly BusinessLayer.Lookup.ILookup_Rooms RoomsBL;

//CTOR
public LookupRoomsController(ILookup_Rooms RoomsBL) {
    this.RoomsBL = RoomsBL;
}

[HttpPost]
public ActionResult CreateRoom(RoomLocationModel room) {
    if (ModelState.IsValid) {
        try {
            // TODO: Add insert logic here    
           
            int? Serial = RoomsBL.Lookup_RoomInsert(room.BuildingFloorID, room.RoomName, room.Min_Capacity, room.Max_Capacity);               
        } catch (Exception error) {
            ViewBag.Messages = error.InnerException.Message;             
        }
    }
    return View();
}

这样,当Lookup_RoomInsert在隔离单元测试中调用时,可以使模拟的不执行任何操作。

[TestMethod()]
public void CreateRoomTestPost() {
    // Arrange
    ILookup_Rooms mock = Mock.Of<ILookup_Rooms>(); //using MOQ

    LookupRoomsController controller = new LookupRoomsController(mock);
  
    RoomLocationModel room = new RoomLocationModel();

    // Act
    ViewResult viewResult = controller.CreateRoom(room) as ViewResult;

    // Assert
    Assert.IsNotNull(viewResult);
}

最后,抽象和实现应该注册到一个 DI 容器中,这样当系统在生产中运行时,实际的实现可以正确地注入到控制器中。


推荐阅读