1

运行单元测试时出现以下错误:用户代码未处理 NullReferenceException。对象引用未设置为对象的实例。

不知道我哪里出错了。请指教。

我的 SessionManager.cs 类

public static int customerID
{
    get
    {
        if (HttpContext.Current.Session != null && 
            HttpContext.Current.Session[_customerID] != null)
        {
            return Convert.ToInt32(HttpContext.Current.Session[_customerID]);
        }
        else
        {
            throw new Ramsell.ExceptionManagement.RamsellException();
        }
    }
    set
    {
        if (HttpContext.Current.Session == null) return;
        HttpContext.Current.Session[_customerID] = value;

    }
}

参与者控制器

public ActionResult Index()
{
     int custId = Convert.ToInt32(SessionManager.customerID);
     //code logic about participant lists
     return View();
}

测试方法 :

 [TestMethod]
    public void IndexTest()
    {
        ParticipantController pCTarget = new ParticipantController();
        const int page = 1;
        const string sortBy = "FirstName";
        const bool ascending = true;
        const string partname = ""; 
        const int success = -1;
        const string id = "";
        var expected = typeof(ParticipantListViewModel);
        ViewResult result = pCTarget.Index(page, sortBy, ascending, partname, success, id) as ViewResult;
        Assert.AreEqual(expected, result.Model.GetType());

    }

//这是我的模拟类

 public Mock<RequestContext> RoutingRequestContext { get; private set; }
 public Mock<HttpContextBase> Http { get; private set; }
    public Mock<HttpServerUtilityBase> Server { get; private set; }
    public Mock<HttpResponseBase> Response { get; private set; }
    public Mock<HttpRequestBase> Request { get; private set; }
    public Mock<HttpSessionStateBase> Session { get; private set; }
    public Mock<ActionExecutingContext> ActionExecuting { get; private set; }
    public HttpCookieCollection Cookies { get; private set; }

    public MockContext()
    {
        this.RoutingRequestContext = new Mock<RequestContext>(MockBehavior.Loose);
        this.ActionExecuting = new Mock<ActionExecutingContext>(MockBehavior.Loose);
        this.Http = new Mock<HttpContextBase>(MockBehavior.Loose);
        this.Server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
        this.Response = new Mock<HttpResponseBase>(MockBehavior.Loose);
        this.Request = new Mock<HttpRequestBase>(MockBehavior.Loose);
        this.Session = new Mock<HttpSessionStateBase>(MockBehavior.Loose);
        this.Cookies = new HttpCookieCollection();

        this.RoutingRequestContext.SetupGet(c => c.HttpContext).Returns(this.Http.Object);
        this.ActionExecuting.SetupGet(c => c.HttpContext).Returns(this.Http.Object);
        this.Http.SetupGet(c => c.Request).Returns(this.Request.Object);
        this.Http.SetupGet(c => c.Response).Returns(this.Response.Object);
        this.Http.SetupGet(c => c.Server).Returns(this.Server.Object);
        this.Http.SetupGet(c => c.Session).Returns(this.Session.Object);
        this.Request.Setup(c => c.Cookies).Returns(Cookies);

        var sessionContainer = new HttpSessionStateContainer("userID", new SessionStateItemCollection(),
                                                new HttpStaticObjectsCollection(), 1, true,
                                                HttpCookieMode.AutoDetect,
                                                SessionStateMode.InProc, false);

        this.Session.Setup(c => c.Add("AspSession", typeof(HttpSessionState).GetConstructor(
                                    BindingFlags.NonPublic | BindingFlags.Instance,
                                    null, CallingConventions.Standard,
                                    new[] { typeof(HttpSessionStateContainer) },
                                    null)
                            .Invoke(new object[] { sessionContainer })));
    }
4

1 回答 1

2

当您为控制器编写单元测试时,您应该单独测试它 - 即应该模拟控制器的依赖项。因此,请确保您的控制器依赖于抽象而不是具体SessionManager实现(使您的类非静态并ISessionManager从管理器类中提取接口):

public interface ISessionManager
{
   int CustomerID { get; set; }
} 

public class HttpSessionManager : ISessionManager
{
    // your current implementation goes here
}

然后模拟这个抽象并将其注入控制器(带 Moq 的示例):

[TestMethod]
public void IndexTest()
{
    var sessionManager = new Mock<ISessionManager>(); // Mock dependency
    sessionManager.Setup(m => m.CustomerID).Returns(42);

    const int page = 1;
    const string sortBy = "FirstName";
    const bool ascending = true;
    const string partname = ""; 
    const int success = -1;
    const string id = "";
    var expectedModelType = typeof(ParticipantListViewModel);
    ParticipantController pCTarget = 
         new ParticipantController(sessionManager.Object); // Inject dependency

    var view = pCTarget.Index(page, sortBy, ascending, partname, success, id)
               as ViewResult;

    sessionManager.VerifyGet(m => m.CustomerID); // Verify dependency was called
    Assert.AreEqual(expectedModelType, view.Model.GetType());
}

这是控制器代码:

public class ParticipantController : Controller
{
    private readonly ISessionManager _sessionManager;

    public ParticipantController(ISessionManager sessionManager) 
    {
        _sessionManager = sessionManager;
    }

    public ActionResult Index()
    {
        int custId = _sessionManager.CustomerID;
        //code logic about participant lists
        return View();
    }
} 

请注意,单元测试的目标是确保代码的每一小部分都按预期工作。如果您将依赖于测试中的其他单元,那么测试可能会因两个原因而失败 - 您的测试单元的行为与预期不符,或者依赖项有问题您已经遇到了这种情况 - 控制器测试失败,因为会话管理器抛出异常。测试表明控制器的行为不像预期的那样。这是真的吗?不 - 它的会话管理器的行为不像预期的那样。

于 2013-04-19T07:16:26.140 回答