Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1909, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Disabilita cookie ShinyStat

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

WPF: Introduzione al pattern Model-View-ViewModel per sviluppatori Visual Basic 2010 - parte 9

Finora abbiamo scritto molto codice, nella serie di post che stiamo trattando relativa a MVVM in WPF con Visual Basic 2010. Ci sono sicuramente delle migliorie da fare e qualche imprecisione da correggere per cui è necessario fare un po' di refactoring prima di passare alla fase finale. Questo ci permetterà, fra l'altro, di scoprire un altro grosso beneficio del pattern MVVM, ossia l'utilizzo di unit tests nei confronti del nostro ViewModel. Partiamo dal refactoring riorganizzando alcune parti del nostro codice.

Refactoring, che passione!

L'attività di refactoring sarà concentrata essenzialmente sui due ViewModel. L'OrdersViewModel, in particolare, è quello che necessita di maggior attenzione. La prima cosa che vogliamo migliorare è l'utilizzo della classe RelayCommand: dal momento che abbiamo fornito un'implementazione generica, è conveniente utilizzare questa al posto di quella non generica. Andiamo quindi nel codice della classe OrdersViewModel e posizioniamoci nell'area che espone le proprietà di tipo ICommand. A titolo esemplificativo riporto il lavoro da eseguire sulla prima, che poi dovrete estendere a tutte le altre. Riscriviamole in questo modo, utilizzando RelayCommand(Of Order):

    Public ReadOnly Property DeleteCommand() As ICommand
        Get
            If _cmdDeleteCommand Is Nothing Then
                _cmdDeleteCommand = New RelayCommand(Of Order)(AddressOf DeleteExecute, AddressOf CanDeleteExecute)
            End If
            Return _cmdDeleteCommand
        End Get
    End Property

Chiaramente va poi modificata la firma dei relativi metodi a cui si punta tramite AddressOf, affinchè ricevano un parametro tipizzato invece che un Object. Quindi li riscriviamo così:

    Private Function CanDeleteExecute(ByVal param As OrderAs Boolean
        If Me.CustomerOrdersView Is Nothing Then Return False
        Return Me.CustomerOrdersView.CurrentPosition > -1
    End Function
      Private Sub DeleteExecute(ByVal param As Order)
        Me.orderAccess.Delete(Me.CustomerOrdersView)
    End Sub

Anche con riferimento ai metodi, dovrete applicare le modifiche a tutti i restanti. Andiamo poi nel gestore di evento chiamato _customersView_CurrentChanged. Estraiamo un nuovo metodo dal contenuto del gestore di evento, per migliorare l'organizzazione del codice e per favorire, se lo vorrete (e vi lascio liberi di provarlo :-)), la creazione di unit test. Il codice diventa quindi il seguente:

    Private Sub _customersView_CurrentChanged(ByVal sender As ObjectByVal e As System.EventArgsHandles _customersView.CurrentChanged
        Me.UpdateOrdersViewAfterCustomerChanged(CType(Me.CustomersView.CurrentItem, Customer))
    End Sub

    Private Function UpdateOrdersViewAfterCustomerChanged(ByVal currentCustomer As CustomerAs Boolean
        Try
            Me.Orders = orderAccess.GetAllOrders(currentCustomer.CustomerID)
            Me.CustomerOrdersViewSource.Source = Me.Orders
            Me.CustomerOrdersView = CType(Me.CustomerOrdersViewSource.View, ListCollectionView)
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

Sempre al fine di favorire la creazione di unit test da eseguire sul ViewModel, invece di invocare dall'interno del costruttore il metodo CustomerDataService.GetAllCustomers, facciamo fare tale invocazione a un nuovo metodo interno al ViewModel che sarà possibile testare e il suo risultato sarà assegnato agli oggetti appropriati. Quindi, per prima cosa spostiamo a livello di classe la seguente dichiarazione:

Private dataAccess As ICustomerDataService

Fatto questo, scriviamo il seguente metodo che restituisce il risultato della chiamata:

    Private Function GetAllCustomers() As IQueryable(Of Customer)
       Return Me.dataAccess.GetAllCustomers
    End Function

All'interno del costruttore, poi, dobbiamo sostituire questo codice:

        Dim dataAccess = GetService(Of ICustomerDataService)()
        Me.orderAccess = GetService(Of IOrderDataService)()
        'Cicla l'elenco dei clienti ottenuto e lo aggiunge
        'alla collezione
        For Each element In dataAccess.GetAllCustomers
            Me._customers.Add(element)
        Next

con il seguente, che sfrutta il precedente metodo:

        Me.dataAccess = GetService(Of ICustomerDataService)()
        Me.orderAccess = GetService(Of IOrderDataService)()
        'Cicla l'elenco dei clienti ottenuto e lo aggiunge
        'alla collezione
        For Each element In Me.GetAllCustomers
            Me._customers.Add(element)
        Next

Niente paura se vi siete persi qualche passaggio, nel prossimo post ci sarà il codice completo da scaricare. Per quanto riguarda il primo ViewModel, il refactoring è completo. Per quanto riguarda l'altro, OrderDetailsViewModel, c'è da applicare l'utilizzo di RelayCommand(Of Order_Detail). I passaggi da eseguire sono gli stessi mostrati all'inizio di questo paragrafo, per cui ve li lascio come esercizio :-)

Scrittura ed esecuzione di unit test

Come sapete, gli unit test ci consentono di testare il funzionamento di porzioni del nostro codice, in modo astratto dal contesto dell'applicazione. Significa quindi che uno unit test verifica il funzionamento del nostro codice senza dover lanciare l'applicazione, in modo totalmente separato, attraverso apposita strumentazione di Visual Studio 2010. Quella di scrivere unit test è sicuramente un'ottima pratica di programmazione e il pattern MVVM sembra fatto apposta per favorire questo tipo di approccio. Provate infatti a pensare a come potreste eseguire degli unit test nei confronti di codice associato alle View, quindi all'interfaccia grafica. Si, forse fattibile, ma comunque legato al contesto della UI. Ora, invece, pensate al metodo GetAllCustomers implementato precedentemente. E' nel ViewModel, quindi non sta nel lato dell'interfaccia, ed è in grado di recuperare dei dati. Quindi è possibile testarne il funzionamento scrivendo uno unit test che verifichi l'effettivo caricamento dei dati, il tutto senza interferire con l'interfaccia. Per quanto molto semplice ed essenziale, quindi assolutamente non strabiliante, questo esempio calza a pennello. Detto questo, andiamo nel nostro OrdersViewModel e facciamo click destro sul metodo GetAllCustomers. Dal menu contestuale selezioniamo la voce Create Unit Test. A questo punto comparirà la dialog illustrata in figura, dalla quale possiamo selezionare ulteriori metodi e, soprattutto, specificare un nome per il progetto di test:

A questo punto Visual Studio 2010 genera il progetto di test, sulle cui caratteristiche non mi soffermo (trovate spiegazioni appropriate in questo mio webcast su Microsoft Be-IT), mentre la prima cosa che dobbiamo fare è copiare il file App.config dal progetto primario, atteso che questo contiene le informazioni di connessione al database, necessarie anche in questo contesto. Successivamente, nel file OrdersViewModelTest.vb andiamo a reperire il metodo chiamato GetAllCustomersTest. Lo scopo del nostro unit test è quello di verificare che il metodo GetAllCustomers carichi effettivamente dei dati dal database e che quindi restituisca un valore non nullo. Riscriviamo quindi il metodo nel modo seguente:

    <TestMethod(), _
     DeploymentItem("adsMVVM_EntityFramework_Complete.exe")> _
    Public Sub GetAllCustomersTest()
        Dim target As OrdersViewModel_Accessor = New OrdersViewModel_Accessor() ' TODO: Initialize to an appropriate value
        Dim actual As IQueryable(Of Customer)
        actual = target.GetAllCustomers
        Assert.IsNotNull(actual)
    End Sub

Ora, utilizzando l'apposita strumentazione di Visual Studio (o semplicemente facendo click destro nel file di codice e cliccando la voce Run Tests del menu contestuale) avviamo l'esecuzione del test. Come si può vedere dalla seguente figura, il test viene superato:

Questo perché effettivamente il metodo GetAllCustomers ha caricato dei dati e quindi restituisce qualcosa che non è null, rispondendo quindi ai requisiti dell'Assert. Come detto, questo è un esempio banale. Tuttavia dovrebbe iniziare a far capire il vantaggio offerto dal pattern MVVM in questi contesti, ossia favorire l'esecuzione del test di porzioni di codice grazie al livello di astrazione raggiunto dal codice stesso, grazie all'intervento del ViewModel.

Fine della parte

Siamo giunti al termine anche della nona parte. Abbiamo migliorato il nostro codice e scritto unit test, vedendo il livello di astrazione che MVVM consente di raggiungere. Nel prossimo post completeremo finalmente il nostro lavoro, predisponendo le View, ossia l'interfaccia grafica. Vedremo ancora qualche scambio di messaggi, molto data-binding e scopriremo il concetto secondo cui la View <> "no code" ma View = "UI code".

Alessandro

Print | posted on lunedì 9 agosto 2010 17:09 | Filed Under [ Visual Basic Windows Presentation Foundation Visual Studio 2010 ]

Powered by:
Powered By Subtext Powered By ASP.NET