我有一个基本控制器,我继承了我的所有控制器。它的工作是基本上设置缓存和错误处理以及检查移动浏览器。
我的用户界面工作正常,但我的单元测试失败。
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应用程序时,这几乎只是在测试中获得的设置。
答案 0 :(得分:2)
假设Request.Browser
是扩展属性,它是抛出异常的逻辑位置之一。或者,IsMobileDevice
的实现尝试在单元测试环境用完时访问null。
编辑查看测试代码后,似乎问题是控制器上的Request
属性从未设置过。当页面由ASP .NET执行时,框架会使用有效对象填充它。在进行单元测试时,您需要为Request
提供一个足以使测试不会崩溃的模拟器。
有两种方法可以做到:
RequestBase
的类,并实现足够的类以生成Browser
没有崩溃。Browser.IsMobile
实际工作的任何功能。我的建议是使用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)
有两种解决方案。
按照Igor提到的那样模拟HTTPRequest实例。
使用反射设置所需的私有设置属性。这对于将一些依赖项直接注入正在测试的主题非常有用。(虽然模拟框架在内部执行此操作)。当您不熟悉Mocking Frameworks时,此方法会有所帮助。
,例如,
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);
希望这有帮助,
谢谢, 维杰