Antonio "tdj"

(C'è sempre un modo migliore)
posts - 312, comments - 268, trackbacks - 17

My Links

News







Tag Cloud

Article Categories

Archives

Post Categories

Image Galleries

Articoli

Blogs

Controlli WinForm free

Guide

Siti vari

Sviluppo

Unit Test con Microsoft Fakes

Qualche giorno fa ho avuto la necessità di fare unit testing su una classe piuttosto semplice: generazione di token con scadenza.
Semplice, fino a quando mi sono ritrovato a fare i conti con la presenza dell'istruzione DateTime.UtcNow.AddMinutes(...) utilizzata per creare una data di scadenza del token. La domanda che mi sono posto è stata "come diavolo faccio a testare qualcosa che dipende dalla macchina su cui è eseguito?".

Nel caso specifico, avevo la necessità di verificare la scadenza di un token con l'assert Token.IsExpired simulando l'esecuzione in due momenti temporali diversi. Che tradotto significava prendere in prestito la DeLorean di Doc per andare a spasso nel tempo :)

Tornando seri, la soluzione, nel caso di Unit Test, è quella di fare il Mock dell'oggetto DateTime, cioè simularne il comportamento con un oggetto equivalente. E durante le mie  ricerche sull'argomento mi sono imbattuto nei Microsoft Fakes.

Cosa sono?

Si tratta di una caratteristica introdotta già con Visual Studio 2012 che, per la verità, avevo già notato senza approfondire più di tanto,  che serve per creare degli assembly fake sia del .Net Framework che di progetti sviluppati da noi, da utilizzare proprio negli Unit Test.

Senza scendere troppo in dettaglio, con gli assembly fakes abbiamo la possibilità di isolare parti di codice del .net framwork mediante l'uso di Stub o Shim.

Vediamo un esempio concreto.
Consideriamo una classe di esempio (sulla falsa riga di quella che ho realmente usato io):

Public Class DemoClass
    
Sub New()
        SetDate()
    
End Sub

    
Private m_DueDate As DateTime
    
Public Property DueDate() As DateTime
        
Get
            
Return m_DueDate
        
End Get
        
Private Set(ByVal value As DateTime)
            m_DueDate = value
        
End Set
    
End Property

    
Private Sub SetDate()
        DueDate = 
DateTime.UtcNow.AddMinutes(5)
    
End Sub

    
Public ReadOnly Property IsExpired As Boolean
        
Get
            
Return DueDate <= DateTime.UtcNow
        
End Get
    
End Property
End Class

Banalmente è una classe che ha una scadenza di 5 minuti dal momento i cui viene istanziata.
Creiamo un nuovo progetto di tip Unit Test e aggiungiamo il nostro progetto Demo come reference.
La nostra esigenza è di fare uno unit test sulla proprietà IsExpired e per farlo dobbiamo simulare il comportamento del tipo DateTime di .Net utilizzando un assembly fake.
Abilitiamo l'opzione Show all files del progetto di test i modo da visualizzare il nodo References del progetto e facciamo click destro sulla reference di System. Dal menu contestuale selezioniamo la voce Add Fakes Assembly:



Dopo qualche secondo il progetto dovrebbe cambiare come segue:



In pratica Visual Studio ha creato le versioni Fake dell'assembly System e mscorlib (da cui dipende System) che saranno utilizzati per i nostri test.

Vediamo allora com'è il codice per testare la proprietà IsExpired:
<TestMethod()>
Public
 Sub Simulate_Expired_Instance()
  
Using ShimsContext.Create()
      
' Imposto la data Utc al 24/10/2013 10:00:00
      
ShimDateTime.UtcNowGet = Function() New DateTime(2013, 10, 24, 10, 0, 0)

      
Dim now As DateTime = DateTime.UtcNow

      
Dim test As New DemoClass

      
' Imposto la data Utc 6 minuti in avanti (al 24/10/2013 10:06:00)
      
ShimDateTime.UtcNowGet = Function() now.AddMinutes(6)

      
Assert.IsTrue(test.IsExpired)
  
End Using
End Sub

Innanzitutto utilizziamo un oggetto di tipo Shim perché non avendo una interfaccia di riferimento per DateTime dobbiamo simularne il comportamento con un oggetto equivalente. Tutti gli oggetti simulati hanno il prefisso ShimXxxxx ed espongono tutte le proprietà ed i metodi dell'oggetto reale ma con la possibilità di ridefinirne il comportamento mediante una lamda expression.
Però, perché tutto funzioni correttamente è necessario creare un contesto di simulazione utilizzando ShimContext.Create() (fondamentale lo Using!).
Nel nostro caso serve ridefinire la data UTC corrente simulando una certa data con questa istruzione:

ShimDateTime.UtcNowGet = Function() New DateTime(2013, 10, 24, 10, 0, 0)

in pratica decidiamo che tutte lechiamate DateTime.UtcNow, all'interno del contesto, restituiscano sempre il valore 24/10/2013 10:00:00. A questo punto diventa semplice simulare momenti temporali diversi e, di conseguenza simulare un intervallo di tempo della durata di oltre 5 minuti (durata massima di una istanza della nostra classe demo) semplicemente intervenendo sulla proprietà UtcNowGet  che viene spostata i avanti di 6 minuti subito dopo la creazione dell'istanza di test (come evidenziato nel codice di esempio precedente).

Eseguendo il nostro test il risultato sarà il seguente:


Per chi volesse approfondire l'argomento: Isolating Code Under Test With Microsoft Fakes

Print | posted on venerdì 25 ottobre 2013 09:32 | Filed Under [ Visual Studio Unit Test ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET