从基础控制器继承时的ASP.NET MVC NullReferenceException

时间:2010-06-15 03:46:55

标签: asp.net-mvc nullreferenceexception

我有一个基本控制器,我继承了我的所有控制器。它的工作是基本上设置缓存和错误处理以及检查移动浏览器。

我的用户界面工作正常,但我的单元测试失败。

Imports System.Web.Mvc

<HandleError()> _
<CompressFilter()> _
<OutputCache(Duration:=30, VaryByParam:="id")> _
Public Class BaseController : Inherits System.Web.Mvc.Controller

    Protected Overrides Function View(ByVal viewName As String, ByVal masterName As String, ByVal model As Object) As System.Web.Mvc.ViewResult
        Dim ismobile As Nullable(Of Boolean) = Request.Browser.IsMobileDevice

        If ismobile Then
            Return MyBase.View(viewName, "Mobile", model)
        Else
            Return MyBase.View(viewName, "Site", model)
        End If

    End Function

End Class

我在单元测试中遇到的错误是Dim ismobile As Nullable(Of Boolean) = Request.Browser.IsMobileDevice

  

对象引用未设置为对象的实例。

编辑:

这是我的测试类的样子

Imports System.Web.Mvc
Imports UrbanNow.Core
Imports Microsoft.VisualStudio.TestTools.UnitTesting

<TestClass()> Public Class EventsControllerTest

    <TestMethod()> Public Sub Index()
        ''# Arrange
        Dim controller As EventsController = New EventsController()

        ''# Act
        Dim result As ViewResult = CType(controller.Index(), ViewResult)

        ''# Assert
        Dim viewData As ViewDataDictionary = result.ViewData
    End Sub
End Class

在创建新的MVC Web应用程序时,这几乎只是在测试中获得的设置。

3 个答案:

答案 0 :(得分:2)

假设Request.Browser是扩展属性,它是抛出异常的逻辑位置之一。或者,IsMobileDevice的实现尝试在单元测试环境用完时访问null。

编辑查看测试代码后,似乎问题是控制器上的Request属性从未设置过。当页面由ASP .NET执行时,框架会使用有效对象填充它。在进行单元测试时,您需要为Request提供一个足以使测试不会崩溃的模拟器。

有两种方法可以做到:

  1. 创建一个派生自RequestBase的类,并实现足够的类以生成Browser 没有崩溃。
  2. 使用模拟框架(如Moq)在运行时创建模拟。您仍然需要实现使Browser.IsMobile实际工作的任何功能。
  3. 我的建议是使用Moq来模拟Request以返回另一个模拟Browser属性的Moq模拟。然后,您只需为IsMobileDevice返回true / false,这样您就可以隔离控制器功能,而无需担心Browser.IsMobileDevice的工作原理。

    C#示例代码:

    Mock<RequestBase> requestMock = new Mock<RequestBase>();
    Mock<Browser> browserMock = new Mock<Browser>();
    requestMock.Setup(request=>request.Browser).Returns(browserMock.Object);
    browserMock.Setup(browser=>browser.IsMobileDevice).Returns(true);
    controller.Request = requestMock.Object;
    

答案 1 :(得分:1)

您是否正确模拟了请求?

答案 2 :(得分:0)

有两种解决方案。

  1. 按照Igor提到的那样模拟HTTPRequest实例。

  2. 使用反射设置所需的私有设置属性。这对于将一些依赖项直接注入正在测试的主题非常有用。(虽然模拟框架在内部执行此操作)。当您不熟悉Mocking Frameworks时,此方法会有所帮助。

  3. ,例如,

      private static void SetPrivateSetPropertyValue(Type type, object obj, string fieldName, object value)
        {
            PropertyInfo propInfo = type.GetProperty(fieldName);
            propInfo.SetValue(obj, value, null);
        }
    

    使用代码

    如,

    this.SetPrivateSetPropertyValue(Request.GetType(),reqInstance,"Browser",browInstance);
    

    希望这有帮助,

    谢谢, 维杰