单元测试:使用Moq

时间:2018-01-23 22:37:57

标签: c# asp.net-mvc unit-testing session moq

我有一个基于某些内部逻辑的函数,在会话变量(Redirect_To)中存储重定向字符串。我正在尝试编写一个单元测试,一旦调用的操作完成,它将检查此会话变量的值。

我正在使用Moq来模拟我的一些属性和功能。但是,每当我使用Moq设置Session变量(Redirect_To)时,它必须将其设置为只读,因为我不能再为其分配值,这导致我的单元测试失败。

这是我的单元测试:

 public async Task Index_ClientTypeIsRPI_ExpectCorrectRedirect()
    {
        var sessionDict = new Dictionary<string, string>
    {
        {"CID", "124" },
        {"UserName", "AK92630" },
        {"REDIRECT_TO", "www.google.com" }
    };

        var controllerContext = HttpContextManager.ReturnMockControllerContextWithSessionVars(sessionDict);

        var mockIdentity = new Mock<IIdentity>();

        mockIdentity.Setup(x => x.Name).Returns("TestName");
        controllerContext.Setup(x => x.HttpContext.User.Identity).Returns(mockIdentity.Object);
        controllerContext.Setup(x => x.HttpContext.User.IsInRole(UserLevel.Subrep.GetDescription())).Returns(true);
        controllerContext.Setup(x => x.HttpContext.Request.Browser.Browser).Returns("InternetExplorer");
        _controller.ControllerContext = controllerContext.Object;
        _iMockManifestManager.Setup(x => x.ReturnSingleMainDataRecordViaTransNoCIDAndUserNameAsync(It.IsAny<string>, It.IsAny<string>, It.IsAny<string>)).ReturnsAsync(New MainData());

        var transNo = "Asdf";
        await _controller.Index(transNo, true, "sd", "dg");

        Assert.AreEqual("www.facebook.com", _controller.HttpContext.Session["REDIRECT_TO"]);
    }

ReturnMockControllerContextWithSessionVars(设置会话变量的函数)

internal static Mock<ControllerContext> ReturnMockControllerContextWithSessionVars(Dictionary<string, object> sessionKeysAndValues):
{
    var fakeHttpContext = HttpContextManager.CreateLocalAuthenticatedUserWithMockHttpContext();
    var controllerContext = new Mock<ControllerContext>;
    controllerContext.Setup(x => x.HttpContext).Returns(fakeHttpContext.Object);
    foreach (var item in sessionKeysAndValues)
    {
        controllerContext.Setup(x => x.HttpContext.Session[item.Key]).Returns(item.Value);
    }

    return controllerContext;
}

动作:

public async Task Index(string transNo, bool? isRechase, string clientID, string clientType)
{
    switch (clientType.ToUpper())
    {
        case "RPI":
            Session["REDIRECT_TO"] = "www.reddit.com";
        break;
        case "LM":
            Session["REDIRECT_TO"] = "www.bbc.co.uk";
        default:
            Session["REDIRECT_TO"] = "www.stackoverflow.com";
            break;
    }

    //Do async stuff

    return null;

}

有人知道如何更改我的代码,所以当我设置Session["Redirect_To"]时,它仍然是可读/写的吗?

另外,我已经从VB.NET转换了这个,但是我能熟练使用这两种语言,所以如果我犯了任何语法错误,那就是免费编写它。如果是这样,请告诉我。

由于

1 个答案:

答案 0 :(得分:1)

创建一个用于会话的存根,因为moq将难以设置用于保存索引属性中的值的集合。其他依赖项应该按照预期使用moq。

class HttpSessionStateMock : HttpSessionStateBase {
    private readonly IDictionary<string, object> objects = new Dictionary<string, object>();

    public HttpSessionStateMock(IDictionary<string, object> objects = null) {
        this.objects = objects ?? new Dictionary<string, object>();
    }

    public override object this[string name] {
        get { return (objects.ContainsKey(name)) ? objects[name] : null; }
        set { objects[name] = value; }
    }
}

使用原始问题库中的示例方法"RPI"作为clientType以下测试已完成并按预期传递。

[TestMethod]
public async Task Index_ClientTypeIsRPI_ExpectCorrectRedirect() {
    //Arrange
    var mock = new MockRepository(MockBehavior.Loose) {
        DefaultValue = DefaultValue.Mock,
    };

    var session = new HttpSessionStateMock();//<-- session stub

    var controllerContext = mock.Create<ControllerContext>();
    controllerContext.Setup(_ => _.HttpContext.Session).Returns(session);

    var _controller = new MyController() {
        ControllerContext = controllerContext.Object
    };

    var transNo = "Asdf";
    var clientID = "123";
    var clientType = "RPI";
    var sessionKey = "REDIRECT_TO";
    var expected = "www.reddit.com";

    //Act
    await _controller.Index(transNo, true, clientID, clientType);
    var actual = _controller.HttpContext.Session[sessionKey].ToString();

    //Assert
    Assert.AreEqual(expected, actual);

}