잊지 않겠습니다.

Controller 객체를 사용해서 각 method를 테스트하는 방법은 매우 뛰어난 테스팅 방법이지만, 불행하게도 Session 및 Identify에 대한 내용을 같이 테스팅 하는 것은 불가능하다. 특히, Session에 Wizard Data 또는 사용자에 따른 개인 정보를 저장하고 있는 경우에는 Controller 객체만을 사용하는 것은 불가능하다.

그래서, Mock을 이용해서 HttpContext를 구성하고, 구성된 HttpContext를 ControllerContext로 구성하여 Controller를 사용하게 되면 위와 같은 문제를 모두 해결 할 수 있다.


public class FakeSession : HttpSessionStateBase
{
    private readonly SessionStateItemCollection _sessionItems;
    public FakeSession(SessionStateItemCollection sessionItems)
    {
        _sessionItems = sessionItems;
    }

    public override void Add(string name, object value)
    {
        _sessionItems[name] = value;
    }

    public override int Count
    {
        get
        {
            return _sessionItems.Count;
        }
    }

    public override IEnumerator GetEnumerator()
    {
        return _sessionItems.GetEnumerator();
    }

    public override NameObjectCollectionBase.KeysCollection Keys
    {
        get
        {
            return _sessionItems.Keys;
        }
    }

    public override object this[string name]
    {
        get
        {
            return _sessionItems[name];
        }
        set
        {
            _sessionItems[name] = value;
        }
    }

    public override object this[int index]
    {
        get
        {
            return _sessionItems[index];
        }
        set
        {
            _sessionItems[index] = value;
        }
    }
    public override void Remove(string name)
    {
        _sessionItems.Remove(name);
        }
}

protected T GetContextedController(T controller, string userName, FakeSession sessionState) where T : ControllerBase
{
    //Register Route
    RouteCollection routes = new RouteCollection();
    MvcApplication.RegisterRoutes(routes);

    //Build Mock HttpContext, Request, Response
    var mockHttpContext = new Moq.Mock();
    var mockRequest = new Moq.Mock();
    var mockResponse = new Moq.Mock();

    //Setup Mock HttpContext 
    mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);
    mockHttpContext.Setup(x => x.Response).Returns(mockResponse.Object);
    mockHttpContext.Setup(x => x.Session).Returns(sessionState);

    if(string.IsNullOrEmpty(userName))
    {
        mockHttpContext.Setup(x => x.User.Identity.IsAuthenticated).Returns(false);
        mockRequest.Setup(x => x.IsAuthenticated).Returns(false);
    }
    else
    {
        mockHttpContext.Setup(x => x.User.Identity.Name).Returns(userName);
        mockHttpContext.Setup(x => x.User.Identity.IsAuthenticated).Returns(true);
        mockRequest.Setup(x => x.IsAuthenticated).Returns(true);
    }
    mockRequest.Setup(x => x.ApplicationPath).Returns("/");

    // Build Request Context
    var ctx = new RequestContext(mockHttpContext.Object, new RouteData());
    controller.ControllerContext = new ControllerContext(ctx, controller);
    return controller;
}


사용 방법은 다음과 같다.
[Test]
public void Start()
{
    _controller = new VirtualMachineController();
    SessionStateItemCollection sessionItemCollections = new SessionStateItemCollection();
    sessionItemCollections[SessionConstants.Account] = _account;
    sessionItemCollections[SessionConstants.ZoneList] = tempZoneList;

    _session = new FakeSession(sessionItemCollections);
    _controller = GetContextedController(_controller, LocalConf.AccountName, _session);
    _controller.Start("tempVmName");
}
Posted by Y2K
,