Reputation: 4223
I'm just getting going with ASP.NET MVC and I'm also new to unit testing :) So far, so good.
I have a controller action that sets up an index view using a viewmodel. Testing the controller action is straight-forward as I can pass a fake service class in the controller's constructor, but my viewmodel is quite complex and fetches it's own service class on instantiation.
Code should make this clearer I hope...
Controller action:
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 class:
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
EDIT:
When testing the controller action, how do I get the viewmodel to use a fake service class?
Should I just ditch the first constructor and always pass in the service from the controller or is there another way?
Cheers,
Nick
Upvotes: 0
Views: 608
Reputation: 3954
I am probably splitting hair, but I would say your model is more a domain model than a view model. Remove the dependency to the IPortalClientService
, or at least do not let the model instantiate it by itself.
I prefer to remove such dependencies away from the view, and over to the controller.
Upvotes: 3
Reputation: 116987
Actually, this is a pattern that we use all the time in our public facing API's, and demonstrates good use of dependency injection. I would pass this in a code review with no problems.
Your implementation gives the user the option to flexibly create the object, and provides for testability.
The only "problem" is that your tests can't easily cover the one line of code in the first constructor, but that's only a problem if you have someone who's fanatical about code coverage - which is usually a problem in itself.
Upvotes: 0