单元测试具有复杂viewModel的控制器操作

时间:2009-07-15 16:27:44

标签: asp.net-mvc unit-testing controller viewmodel

我刚刚开始使用ASP.NET MVC而且我也是单元测试的新手:)到目前为止,非常好。

我有一个控制器操作,使用viewmodel设置索引视图。测试控制器动作是直截了当的,因为我可以在控制器的构造函数中传递假服务类,但我的viewmodel非常复杂并且在实例化时获取它自己的服务类。

代码应该让我更清楚,我希望......

控制器操作:

Function Index(ByVal id As Integer?) As ActionResult
  Dim totalCount As Integer = 0
  Dim selectedClient As Integer
  If id Is Nothing Then
    selectedClient = _portalClientService.GetFirstClient().ID
  Else
    selectedClient = id
  End If
  Dim users As MembershipUserCollection = _membershipService.GetUsersByClientId(selectedClient, 0, 1000, totalCount)
  Return View(New UserListViewModel(users, selectedClient))
End Function

Viewmodel类:

Public Class UserListViewModel

  Private _clientService As IPortalClientService

  Public Sub New(ByVal users As MembershipUserCollection, ByVal selectedClient As Integer)
    Me.New(users, selectedClient, Nothing)
  End Sub

  Public Sub New(ByVal users As MembershipUserCollection, ByVal selectedClient As Integer, ByVal clientService As IPortalClientService)
    _users = users
    _clientService = If(clientService, New PortalClientService)
    _clients = New SelectList(_clientService.GetClients.OrderBy(Function(c) c.ClientName), "ID", "ClientName", selectedClient)
  End Sub

  Private _users As MembershipUserCollection
  Public Property Users() As MembershipUserCollection
    Get
      Return _users
    End Get
    Set(ByVal value As MembershipUserCollection)
      _users = value
    End Set
  End Property

  Private _clients As SelectList
  Public Property Clients() As SelectList
    Get
      Return _clients
    End Get
    Set(ByVal value As SelectList)
      _clients = value
    End Set
  End Property

End Class

编辑:

在测试控制器操作时,如何让viewmodel使用假服务类?

我应该抛弃第一个构造函数并始终从控制器传递服务,还是有另一种方式?

干杯,
尼克

2 个答案:

答案 0 :(得分:3)

我可能会分裂头发,但我会说你的模型更像是一个域模型而不是一个视图模型。删除对IPortalClientService的依赖关系,或者至少不让模型自己实例化它。

我更喜欢将这些依赖项从视图中删除,然后再移到控制器上。

答案 1 :(得分:0)

实际上,这是我们在面向公众的API中一直使用的模式,并且演示了依赖注入的良好用法。我会在代码审查中通过这个,没有任何问题。

您的实现为用户提供了灵活创建对象的选项,并提供了可测试性。

唯一的“问题”是你的测试不能轻易覆盖第一个构造函数中的一行代码,但如果你有一个对代码覆盖率狂热的人 - 这通常本身就是一个问题,那么这只是一个问题。