【问题标题】:MVC: How to mock after using HttpContextWrapper conversionMVC:使用 HttpContextWrapper 转换后如何模拟
【发布时间】:2013-11-12 19:18:07
【问题描述】:
Public Class PhotoUploadController

   Public ReadOnly Property IsMobileDevice As Boolean
       Get
          Return ControllerContext.HttpContext.GetOverriddenBrowser.IsMobileDevice
       End Get
   End Property

   Function SavePhoto(model As PhotoUploadModel) As ActionResult
       If Not String.IsNullOrWhiteSpace(Request.Files(0).FileName) And IsMobileDevice Then
    Return View("Index", model)
   End If       
   End Function

End Class   

<TestMethod()>
 Public Sub SavePhoto_Test()

   Dim permissions As New List(Of String)
   permissions.Add(Constants.VIEW_ACCOUNTS)
   Dim mUser As New MockUser(ListOfPermissions:=permissions)
   Dim controller As PhotoUploadController = New PhotoUploadController(mUser, New PhotoRepository)
   System.Web.HttpContext.Current = New HttpContext(New HttpRequest("test", "http://www.yahoo.com/accounts", ""), New HttpResponse(New System.IO.StringWriter()))

   Dim browserMock = MockRepository.GenerateStub(Of HttpBrowserCapabilities)()
   browserMock.Expect(Function(b) b.IsMobileDevice).Return(True)
   System.Web.HttpContext.Current.Request.Browser = browserMock

   Dim currentContext As HttpContextBase = MockRepository.GenerateStub(Of HttpContextWrapper)(System.Web.HttpContext.Current)
   currentContext.Expect(Function(fn) fn.Request.Files(0).FileName).Return("test.txt")
   'If I comment out the two lines above and uncomment the below line the IsMobile is set in the SavePhoto actionresult otherwise it is null.
   'Dim currentContext As HttpContextBase = New HttpContextWrapper(System.Web.HttpContext.Current)
   controller.ControllerContext = New ControllerContext(currentContext, New System.Web.Routing.RouteData(), controller)

   Dim model As New PhotoUploadModel(mUser)

   Dim result As ActionResult = controller.SavePhoto(model)

   Assert.IsNotNull(result)
   Assert.IsInstanceOfType(result, GetType(ViewResult))

End Sub

【问题讨论】:

  • 根据例外情况,它不是模拟对象。您需要创建模拟对象。如果你使用 Rhino Mock,你可以使用 MockRepository.GenerateStub(); ?
  • 当我在代码中调用此对象时,新错误 ControllerContext.HttpContext.GetOverriddenBrowser.IsMobileDevice 为 null。为什么 GenerateStub 会删除我传递给 System.Web.HttpContext.Current 的浏览器信息?如果我删除 GenerateStub 并将这个 Dim currentContext 添加为 HttpContextBase = New HttpContextWrapper(System.Web.HttpContext.Current)。 ControllerContext.HttpContext.GetOverriddenBrowser.IsMobileDevice 有一个值。我添加浏览器模拟代码的原因。
  • 嗨@user2868558,您能否使用完整的单元测试和被测系统提供/更新您的问题(当然省略任何敏感信息)。没有看到你的代码就很难给你一个完整的答案。
  • 我取出了一些代码。出于某种原因,这里的编辑不喜欢我写的一些项目。所以它看起来不像上面的代码。我设置了 IsMobileDevice 但我需要模拟上下文以添加文件名。出于某种原因,我不能两者都做。

标签: asp.net-mvc unit-testing rhino-mocks


【解决方案1】:

以下答案应该会引导您走向正确的方向。 请注意,我不是 VB.NET 开发人员。如果我的语法不正确,请耐心等待。我实际上使用了一个工具将 C# 转换为 VB :)

首先你的单元测试有几个问题

一个。您的测试方法名称写得不好,它不能反映您的确切意图。

b.存根/设置期望并不容易

ControllerContext.HttpContext.GetOverriddenBrowser.IsMobileDevice

GetOverriddenBrowser 是一种静态扩展方法。所以它是不可模拟的。

c。您的断言正在验证两件事。一是结果是否为null,二是结果的类型是ViewResult。我会亲自测试后者,结果的类型。如果结果不是,测试会以任何方式抛出异常。通过限制为一个断言,您可以更轻松地编写测试方法名称。

为了避免删除 .IsMobileDevice 的痛苦,我将简单地在控制器中引入一个属性/或多或少一个 Func/delegate 属性。我会在构造函数中设置 IsMobileDevice,如下所示。这样我就可以在我的单元测试中简单地存根从 IsMobileDeviceFunc 返回的值。

Imports System.Web.WebPages

Public Interface IUser
End Interface

Public Interface IPhotoRepository
End Interface

Public Class PhotoUploadModel
End Class

Public Class PhotoUploadController
    Inherits Controller

    Private m_IsMobileDeviceFunc As Func(Of Boolean)

    Public Sub New(user As IUser, repository As IPhotoRepository)
        IsMobileDeviceFunc = Function() 
        ControllerContext.HttpContext.GetOverriddenBrowser().IsMobileDevice
    End Sub

    Public Property IsMobileDeviceFunc() As Func(Of Boolean)
        Get
            Return m_IsMobileDeviceFunc
        End Get
        Set(value As Func(Of Boolean))
           m_IsMobileDeviceFunc = Value
        End Set
    End Property


    Public Function SavePhoto(model As PhotoUploadModel) As ActionResult
       Dim isMobD = IsMobileDeviceFunc

       If Not String.IsNullOrWhiteSpace(Request.Files(0).FileName) And isMobD() Then
           Return View("Index", model)
       End If

       Return New EmptyResult()
    End Function

End Class

单元测试

 <TestMethod()> Public Sub SavePhoto_ActionExecute_ActionResultIsTypeOfViewResult()

    Dim sut = New PhotoUploadController(MockRepository.GenerateStub(Of IUser)(), MockRepository.GenerateStub(Of IPhotoRepository)())
    sut.IsMobileDeviceFunc = Function() True
    Dim currentContext = MockRepository.GenerateStub(Of HttpContextBase)()
    Dim requestStub = MockRepository.GenerateStub(Of HttpRequestBase)()
    requestStub.Expect(Function(x) x.Files(0).FileName).[Return]("foo")
    currentContext.Expect(Function(x) x.Request).[Return](requestStub)
    sut.ControllerContext = New ControllerContext(currentContext, New RouteData(), sut)

    Dim result As ActionResult = sut.SavePhoto(New PhotoUploadModel())

    Assert.IsInstanceOfType(result, GetType(ViewResult))
 End Sub

希望这会为您指明正确的方向。

【讨论】:

  • 在构造函数中,ControllerContext.HttpContext.GetOverriddenBrowser.IsMobileDevice在我启动网站时抛出NullReferenceException。
  • @user2868558 谢谢,有一些小的语法问题(不是 VB 专家),但我用完全编译代码更新了解决方案。你不应该得到错误。请查看完整的解决方案和通过测试。
猜你喜欢
  • 2016-01-04
  • 1970-01-01
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 2020-07-14
  • 2013-02-13
  • 1970-01-01
相关资源
最近更新 更多