Unit test su HttpModule ed un HttpHandler

Print Content | More

ASP.NET MVC ha aperto un mondo nuovo allo sviluppo di applicazioni web, ossia quello del testing. Di fatto, grazie ad MVC sono stati astratti alcuni concetti che precedentemente impedivano la testabilità delle webforms.

Purtroppo anche con MVC alcune cose rimangono scomode da testare, come gli HttpModule e HttpHandler; anzi, nella normale implementazione non sono proprio testabili. Cercando un po’ in rete ho scovato questo post, che mostra un approccio molto elegante su come effettuare Unit Test anche sui moduli e sugli handler, ma procediamo per gradi.

Con l’uscita del  ServicePack 1 del .NET Framework è stata introdotta una nuova libreria, la “System.Web.Abstraction”, contenente una serie di wrapper che hanno lo scopo di impedire l’utilizzo diretto di alcune classi (come l’HttpContext) e, di conseguenza, permettono di testare del codice precedentemente non testabile (HttpModule e HttpHandler).
Per far ciò è necessario creare delle classi base da cui tutti i Module/Handler andranno ad ereditare e gestire gli eventi a livello di baseclass, permettendo così un’eventuale override della classe concreta nel caso del Module, o un’implementazione nel caso dell’Httphandler. Nell’esempio seguente viene mostrata la base classe per un HttpModule:

/// <summary>
///        The base class for the HttpModules
/// </summary>
public abstract class BaseHttpModule : IHttpModule
{
    #region IHttpModule Members

    /// <summary>
    /// Initializes a module and prepares it to handle requests.
    /// </summary>
    /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param>
    public void Init(HttpApplication context)
    {
        context.BeginRequest += (sender, e) => OnBeginRequest(new HttpContextWrapper(((HttpApplication)sender).Context));
        context.Error += (sender, e) => OnError(new HttpContextWrapper(((HttpApplication)sender).Context));
        context.EndRequest += (sender, e) => OnEndRequest(new HttpContextWrapper(((HttpApplication)sender).Context));
    }

    /// <summary>
    /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
    /// </summary>
    public virtual void Dispose()
    {
    }

    #endregion

    /// <summary>
    /// Method called when a server receive a webrequest before other requests
    /// </summary>
    /// <param name="context">The context.</param>
    public virtual void OnBeginRequest(HttpContextBase context)
    {
    }

    /// <summary>
    /// Method called when an error occurred.
    /// </summary>
    /// <param name="context">The context.</param>
    public virtual void OnError(HttpContextBase context)
    {
    }

    /// <summary>
    /// Method called when a server receive a webrequest and all methods in the request life cycle are completed.
    /// </summary>
    /// <param name="context">The context.</param>
    public virtual void OnEndRequest(HttpContextBase context)
    {
    }
}

Da qui l’implementazione di un Module (nell’esempio il ReferrerModule di dexter semplificato) è piuttosto banale, l’unica differenza è che invece di agganciare un evento va effettuato l’override del metodo virtual presente sulla classe base, come mostrato di seguito:

public class ReferrerModule : BaseHttpModule
{
    private ILogger logger;
    private ITraceService traceService;
    private IUrlBuilderService urlbuilder;

    public ILogger Logger
    {
        get { return logger ?? (logger = IoC.Resolve<ILogger>()); }
    }

    public ITraceService TraceService
    {
        get { return traceService ?? (traceService = IoC.Resolve<ITraceService>()); }
    }

    public IUrlBuilderService Urlbuilder
    {
        get { return urlbuilder ?? (urlbuilder = IoC.Resolve<IUrlBuilderService>()); }
    }

    public ReferrerModule ()
    {
    }

    public ReferrerModule ( ILogger logger , ITraceService traceService , IUrlBuilderService urlbuilder )
    {
        this.logger = logger;
        this.traceService = traceService;
        this.urlbuilder = urlbuilder;
    }

    public override void OnEndRequest ( HttpContextBase context )
    {
        base.OnEndRequest ( context );

        if (context.Request.UrlReferrer != null)
            TraceService.AddReferrer(url.ToString(), referrer.ToString());
    }
}

A questo punto il test è facilmente scrivibile, come mostrato sotto:

[TestMethod]
public void OnEndRequest_WithValidRequestUrl_ShouldInvokeTheServiceMethod()
{
    //Arrage
    var httpContext = MockRepository.GenerateStub<HttpContextBase> ();
    var httpRequest = MockRepository.GenerateStub<HttpRequestBase>();
    var httpResponse = MockRepository.GenerateStub<HttpResponseBase>();

    httpContext.Expect ( x => x.Request ).Return ( httpRequest );
    httpContext.Expect(x => x.Response).Return(httpResponse);
        
    Uri currentUrl = new Uri ( "http://www.tostring.it");
    Uri urlReferrer = new Uri ( "http://www.bing.com/search?q=imperugo");
    
    httpRequest.Expect ( x => x.Url ).Return ( currentUrl ) );
    httpRequest.Expect ( x => x.UrlReferrer ).Return ( urlReferrer ) );

    ITraceService traceService = MockRepository.GenerateMock<ITraceService> ();

    var module = new ReferrerModule (
        MockRepository.GenerateStub<ILogger> () ,
        traceService ,
        MockRepository.GenerateStub<IUrlBuilderService> ()
        );

    //Act
    module.OnBeginRequest(httpContext);

    //TODO:Assert
    traceService.AssertWasNotCalled(x => x.AddReferrer(Arg<Uri>.Is.Equal(currentUrl), Arg<Uri>.Is.Equal(urlReferrer)));
    
}

Come potete vedere, se si ha la necessità di iniettare delle dipendenze potete creare un secondo costruttore che accetti l’instanza della dipendenza e gestire l’eventuale null nella property di get o nel costruttore parameterless (nel mio caso ero obbligato a gestire la dipendenza dalle properties perchè non avevo ancora inizializzato l’IoC Container al momento in cui l’HttpModule viene registrato nell’applicazione, problema che in Dexter si andrà a risolvere nelle prossime release).

Per quanto riguarda un HttpHandler l’approccio è esattamente lo stesso, classe base, metodi virtual ed override.

/// <summary>
///        The base class for the HttpHandlers
/// </summary>
public abstract class HttpHandlerBase : IHttpHandler
{
    #region IHttpHandler Members

    /// <summary>
    /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
    /// </summary>
    /// <value></value>
    /// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
    /// </returns>
    public virtual bool IsReusable
    {
        get { return false; }
    }

    /// <summary>
    /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
    /// </summary>
    /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
    public void ProcessRequest(HttpContext context)
    {
        ProcessRequest(new HttpContextWrapper(context));
    }

    #endregion

    /// <summary>
    /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
    /// </summary>
    /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
    public abstract void ProcessRequest(HttpContextBase context);
}

Buopn Testing
Ciauz

.u


ASP.NET , MVC , Unit Test , Testing , HttpModule , HttpHandler

2 comments

Testmex => tab (snippet)

Print Content | More

In questo periodo sto scrivendo test in continuazione, un po’ perchè sto leggendo il libro di Roy OsheroveThe Art of Unit Test”, ed un po’ perchè sto cercando di colmare un gap su dexter. Chi mi frequenta pensa che ormai sono vittima del testing in quanto non faccio altro che parlare di unit test, di come scrivere test, etc., e devo ammettere che un po’ è anche vero :).

Il tutto è partito da una certa persona (un po’ contabile ed un po’ commercialista :D) che mi ha spronato più e più volte a guardare lo sviluppo anche da una prospettiva differente, ossia da quella del testing...per questo  non posso che ringraziarlo, anche se per assimilare bene i concetti e metterli in pratica ho impiegato un po’ di tempo, ma credo che sia del tutto normale.

Parlando dell’aspetto pragmatico dei test scritti in questi giorni, posso dire che hanno una cosa che li contraddistingue, ossia la presenza di SharpTestEx e RhinoMock; di fatto mi sono creato uno snippet che mi creasse a sua volta un metodo con la struttura secondo la mia nomenclatura preferita e, nel caso mi aspettassi un’eccezione dal test, mi implementasse anche il controllo della stessa.
Per farla breve tutti i miei test devono avere un nome leggibilissimo, che rispecchi il più possibile i tre aspetti base, quindi far capire cosa si sta testando, con quali valori e cosa ci si aspetta:

“MethodUnderTest_Scenario_ExpectedBehavior”

In un esempio pratico in cui si voglia testare un metodo “GetList”, passando un valore negativo al parametro “pageSize” e aspettandosi dal metodo da testare un’eccezione, il nome del test dovrebbe essere una cosa tipo: “GetList_WithNegativePageSize_ShouldThrowArgumentOutOfRangeException” che, tradotto in soldoni, dovrebbe essere implementato più o meno così:

[TestMethod]
public void GetList_WithNegativePageIndex_ShouldThrowNewArgumentOutOfRangeException()
{
    //TODO:Arrage

    //TODO:Act

    //TODO:Assert
    ActionAssert.Throws<ArgumentOutOfRangeException>(() => something).ParamName.Should().Be.EqualTo("pageSize");
}

Purtroppo anche con il copia/incolla può essere scomodo ripetere ogni volta questo codice, così mi sono deciso a scrivere uno snippet che, digitando !testmex + tab!, mi crea automaticamente lo scheletro.

Di seguito lo snippet che possiamo copiare ed incollare direttamente nell’apposita folder

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
            <Title>Test Method With Exception Management</Title>
            <Shortcut>testmex</Shortcut>
            <Description>Code snippet for a test method with Exception </Description>
            <Author>Ugo Lattanzi</Author>
        </Header>
        <Snippet>
            <Imports>
                <Import>
                    <Namespace>SharpTestsEx</Namespace>
                </Import>
                <Import>
                    <Namespace>Rhino.Mocks</Namespace>
                </Import>
            </Imports>
            <References>
                <Reference>
                    <Assembly>SharpTestsEx.MSTest.dll</Assembly>
                    <Assembly>Rhino.Mocks.dll</Assembly>
                </Reference>
            </References>
            <Declarations>
                <Literal>
                    <ID>MethodName</ID>
                    <ToolTip>Replace with the name of the test method</ToolTip>
                    <Default>MethodName</Default>
                </Literal>
                <Literal>
                    <ID>StateUnderTest</ID>
                    <ToolTip>Replace with the state under test name</ToolTip>
                    <Default>StateUnderTest</Default>
                </Literal>
                <Literal>
                    <ID>ExpectedParameterName</ID>
                    <ToolTip>Replace with the expected exception parameter name</ToolTip>
                    <Default>ExpectedParameterName</Default>
                </Literal>
                <Literal>
                    <ID>ExceptionType</ID>
                    <ToolTip>Exception type</ToolTip>
                    <Function>SimpleTypeName(global::System.Exception)</Function>
                </Literal>
            </Declarations>
            <Code Language="csharp">
                <![CDATA[[TestMethod]
          public void $MethodName$_$StateUnderTest$_ShouldThrowNew$ExceptionType$()
        {
            //TODO:Arrage
            
            //TODO:Act
            
            //TODO:Assert
            ActionAssert.Throws<$ExceptionType$> ( () => something ).ParamName.Should().Be.EqualTo ( "$ExpectedParameterName$" );
          }]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

enjoy the snippet!

Ciauz


Visual Studio , Snippet , Testing , SharpTestEx , Unit Test

3 comments

Disponibile il mio webcast su ASP.NET MVC 2

Print Content | More

Ho scoperto solo questo weekend la pubblicazione di un mio webcast su MVC intitolato “ASP.NET MVC 2: Powerful data form” sul portale BEIT di Microsoft.
Devo dire di essere particolarmente contento per aver avuto la possibilità di registrare questo webcast (il primo per me) e ringrazio partiolarmente Pietro per avermi dato la fiducia e la possibilità.
Ovviamente se qualcuno ha feedback, domande, etc mi trovate qui.

image


MVC , Webcast

0 comments

Un’odissea chiamata Boot-Camp

Print Content | More

Provo a raccontare un po’ quanto già detto da Paperino qui.

Poco più di una settimana fa mi è arrivato il fatidico MacBook Pro aziendale, ordinato a metà febbraio (core i7, 8gb di Ram, 500gb di disco, etc). Ad un primo impatto devo dire che il prodotto è di ottima fattura, che sia bello è inutile negarlo, il monitor spettacolare, scheda audio ottima, tastiera scomoda (per l’utente windows) ma illuminata e abbastanza sensibile.
Nel complesso devo dire proprio un bel prodotto. Ora, la domanda che normalmente mi fanno quando dico che ho un MacBook Pro è: “ma come mai un Mac quando lavori con Windows?”

Beh la risposta nasce dall’esigenza di mercato, il Mac inizia ad essere “diffuso”, l’esigenza di dover sviluppare un qualcosa per iPhone è una realtà, e poi diciamolo, sul Mac “gira” anche Windows!

Proprio su questo argomento devo dire che la società di Cupertino non è che possa tanto impedire l’installazione di Windows, dato che l’hardware è il medesimo di tantissimi altri pc, e quindi ha ben pensato di creare una dipendenza del sistema operativo di Redmond da loro; di fatto, ad oggi non è possibile utilizzare Windows su un prodotto Mac senza utilizzare i loro drivers.

Il motivo è piuttosto semplice: pur trattandosi dello stesso hardware, gli ID sono differenti da quelli presenti su tutti i pc, e, di fatto, se si prova ad installare il driver della scheda video nVidia su un Mac, si riceve un bel messaggio che comunica all’utente la non presenza della scheda per la quale si sta tentando di installare il driver; se si prova a far cercare a Windows stesso il driver, la musica non cambia perchè c’è sempre quell’HW ID sconosciuto, quindi bisogna arrendersi ed installare i drivers Apple.

Ad un primo impatto ho pensato: “vabbè, sarà solo la scheda video, pazienza!”, invece neanche a pensarci… tutto l’hardware che riporto di seguito necessita dei drivers Boot-Camp:

  • Apple Bluetooth;
  • Apple Keyboard Support;
  • Apple Remote Driver;
  • Apple Trackpad;
  • Atheros 802.11 Wireless;
  • Boot Camp control panel for Microsoft Windows;
  • Boot Camp System Task Notification item (System Tray);
  • Broadcom Wireless;
  • Intel Chipset Software;
  • Intel Integrated Graphics;
  • iSight Camera;
  • Marvel Yukon Ethernet;
  • nVidia Graphics;
  • Cirrus Logic Audio;
  • Realtek Audio;
  • SigmaTel Audio;
  • Startup Disk control panel for Microsoft Windows

Direi un bel po’ di roba che, con i drivers scritti da Apple, funziona malissimo in ambiente Windows; tantissimi errori del Bluetooth (il Magic Mouse impazzisce), che mi hanno portato anche a resettare la PRAM con una valangata di problemi a seguire (periferiche viste due volte, schede non riconosciute, il tool di boot-camp che ignora i settaggi), schermate blu a go go, per non parlare della durata della batteria che sotto Windows è di 3.5 ore, mentre con OSX è di ben 7.5 ore.

Direi un netta differenza di durata, e a quel punto mi son detto : “possibile che Windows consumi così tanto"?”; indagando un po’ ho scoperto, grazie allo spione di “powercfg –energy”, che tutte le periferiche con driver firmato Apple non permettono al sistema operativo di gestire il loro consumo energetico e di conseguenza di disabilitarne alcune allo scopo di preservare la durata della batteria.

Per chi fosse ancora dubbioso sul fatto che un driver non può influire tanto sul funzionamento di una periferica, dico solo che sotto OSX con un disco Firewire il transfer-rate è di 55 Mb/sec, sotto Windows, con la stessa porta e lo stesso Hard Disk, è di 15 Mb/sec (il buon Mauro ne può raccontare molte altre…)!

Ad oggi, dopo 10gg, ho formattato 2 volte la partizione Windows, ed ho tutte le periferiche di rete doppie.

Da qui è nata la domanda: “ma quando un utente prova un computer Apple con dentro Windows e si accorge di quanto possa andare male, cosa pensa?”
Per la risposta leggete qui.

enjoy your Mac!


BootCamp , Windows , Apple

5 comments

Aero, Power Saver e Windows 7

Print Content | More

Se, per qualche strano motivo, quando cambiate la modalità di utilizzo del vostro portatile impostandola in “Power Saver”, Aero rimane attivo invece di disabilitare alcuni effetti, come la trasparenza (causando un ovvio consumo di batteria in più), potete risolvere il problema seguendo passo passo i seguenti step:

  1. Be sure you don't have an unsaved theme in the personalization window. In that case delete it.
  2. Save your theme if you didn't do yet.
  3. Switch to balanced power plan if you are using another plan.
  4. Select Windows 7 and switch back to your theme then. Keep power options and personalization windows open.
  5. Now change power plan to power saver
  6. In personalization window -> window color and and disable trasparency. Click save changes. You can see that an unsaved theme has just been created and activated.
  7. Select balanced power plan.
  8. Activate your theme, delete the unsaved theme and close personalization window.

Sembra una cosa assurda, ma funziona :)

Fonte: http://social.technet.microsoft.com/Forums/en-US/w7itproperf/thread/e11d6d0c-b3ac-4e44-8912-ef64e6484e5b


Windows 7

0 comments

SharpTestEx e Visual Studio 2010

Print Content | More

Già dal post precedente si capiva che ho avuto problemi con SharpTestEx e Visual Studio 2010. Nello specifico il problema era dovuto al fatto che il Framework di testing cercava di caricare un’assembly non presente nel mio computer, in quanto disponibile con Visual Studio 2008 che non ho avuto ancora il tempo di installare (maggiori info qui).

Detto ciò, dopo uno scambio di email con il disponibilissimo Fabio Maulo, siamo giunti a due soluzioni possibili:

  1. Scaricare e ricompilare il progetto;
  2. Effettuare un redirect del binding;

Per ovvi motivi di tempo ho optato per la seconda soluzione, già spiegata nel bug di codeplex, ma che riporto qui di seguito:

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
            <assemblyIdentity name="Microsoft.VisualStudio.QualityTools.UnitTestFramework" 
                    publicKeyToken="b03f5f7f11d50a3a" 
                    culture="neutral" />
             <bindingRedirect oldVersion="9.0.0.0"
                    newVersion="10.0.0.0"/>
        </dependentAssembly>
    </assemblyBinding>
</runtime>

Enjoy SharpTestEx.


Visual Studio 2010 , SharpTestEx , Unit Test

0 comments

Assembly Binding Log Viewer (spettacolo).

Print Content | More

Ametto la mia totale ignoranza a riguardo, ma purtroppo ho scoperto solo ieri l’esistenza di questo tool (fighissimo) che mi ha permesso di risolvere un problema in pochi istanti; ma partiamo con ordine.

La settimana scorsa mi è arrivato il portatile aziendale ed ovviamente c’è stata tutta la trafila di installazione di quei tools fondamentali per il lavoro, quindi Visual Studio, Reflector, Sql, etc.
Forse perchè lo uso un po’ meno, però ho tralasciato l’installazione di Visual Studio 2008 (in azienda siamo su 2010 e per i miei sfoghi tecnologici non uso sicuramente la 2008).

Una volta reso abile ed arruolato il pc per lavorare, ho deciso di mettermi a scrivere un po’ di test: tutti i test che precedentemente andavano hanno deciso di non andare e, dalla test detail view, si poteva notare che il problema era riconducibile ad un’assemlby ben precisa “Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0”, ed il messaggio di errore era il seguente:

Test method Dexter.Core.UI.Framework.Test.Services.PostServiceTest.Get_list_with_valid_data_should_raise_post_retrieved_list_event threw exception:
System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

La prima domanda è stata: come mai c’è qualcosa che sta referenziando la versione 9.0.0.0 dello UnitTestFramework quando tutto il progetto è su .NET Framework 4.0? Ma sopratutto chi lo stava facendo?

Il buon Gian Maria mi ha indirizzato verso questo tool (per avviarlo è sufficiente digitare dal prompt di Visual Studiofuslogvw”), che permette di abilitare e consultare il Binding Log tramite una UserInterface, senza andare di conseguenza ad agire manualmente sulle chiavi di registro. Di fatto, dopo aver impostato il livello di logging nella finestra dei settings e rieseguito i test, la finestra del tool si è popolata come da screenshot:

image

La cosa bella è che facendo doppio click sulla voce interessata all’interno della lista viene aperto un ulteriore dettaglio che permette di individuare chi referenzia l’assembly mancante.

image

 

 

In questo caso SharpTestEx.MSTest.

Ciauz


Tools , Unit Test , Visual Studio

0 comments

Esecuzione parallela di Unit Test in Visual Studio 2010

Print Content | More

Molto probabilmente ne avranno parlato in tanti, ma scopro solo ora che in Visual Studio 2010 è possibile eseguire più Unit Test contemporaneamente se si ha a disposizione una o più CPU MultiCore; ma partiamo con ordine e vediamo come nasce questa esigenza e in quali casi tale approccio può aiutarci.
Dato il continuo aumentare dei test in Dexter, alcuni dei quali impiegano un tempo piuttosto alto (es: gli Smock Test, che verificano il funzionamento di tutte le skin e dei metodi asincroni), mi sono chiesto se era possibile far sì che l’esecuzione di tutti questi test non fosse seriale ma parallela, in modo da ridurre il tempo di esecuzione. Fortunatamente “sbingando” un po’ ho trovato questo interessantissimo post che spiega come la cosa sia fattibile con Visual Studio 2010.

I test sono una cosa seria :), e prima di scegliere un approccio del genere è necessario sapere che l’esecuzione parallela dei test richiede che alcune regole siano rispettate, quindi è bene sapere che essa:

  • è utilizzabile solo in macchine multi Core/CPU;
  • richiede che tutti i test siano Thread Safe;
  • è utilizzabile solo per gli Unit Test (quindi gli Smock Test non ne trarrebbero beneficio);
  • è utilizzabile solo per i test in esecuzione sulla propria macchina;
  • richiede che i Data Adapter siano disabilitati;

Per tutta questa serie di motivi questa opportunità non è attiva di default, e quindi è necessario andare specificare che tutte le regole sopra elencate sono state rispettate e che vogliamo eseguire più test in parallelo.

Per prima cosa è necessario andare a modificare la configurazione dei nostri test e disabilitare i “Data Adapter”; per far ciò è sufficiente fare doppio Click sul file “.testsetting” presente all’interno della nostra solutions: a questo punto dovrebbe aprirsi una finestra come la seguente, dove dobbiamo disabilitare tutte le checkbox presenti all’interno della scheda “Data and Diagnostics”:

image

Completato questo step è ora necessario modificare nuovamente lo stesso file, ma tramite l’editorXML, in quanto l’opzione che andremo ad impostare non è configurabile tramite la UI presente in Visual Studio.
Quindi click con il destro sullo stesso file e selezione della voce “Open With”, ed a quel punto scelta della voce “XML (text) Editor”; da qui in poi è possibile andare a cambiare la configurazione dei test e modificare il nodo Execution, specificando l’attributo “parallelTestCount” ed impostandogli come valore il numero di Core/CPU che si intende utilizzare per l’esecuzione dei test (impostando 0 come valore, sarà il sistema a stabile il numero di Core/CPU da utilizzare).

A questo punto siamo abili ed arruolati per eseguire UnitTest in parallelo.
VS2010 Rulez!

Ciauz


Visual Studio 2010 , Unit Test

2 comments

Alcuni problemi con l’AntiForgeryToken in ASP.NET MVC 2

Print Content | More

È un po’ che ho “in canna” questo post, ma l’ultimo periodo è stato veramente intenso e non mi ha concesso molto tempo per poter postare.

L’argomento in questione è l’utilizzo dell’attributo (o l’helper) AntiForgeryToken sul porting di applicazioni MVC2, che può causare non pochi problemi in fase di deploy di applicazioni distribuite.

Nello specifico si rischia di incappare in una serie di errori 500 come quello mostrato di seguito:

[InvalidCastException: Unable to cast object of type 'System.Web.UI.Triplet' to type 'System.Object[]'.]
   System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) +104

[HttpAntiForgeryException (0x80004005): A required anti-forgery token was not supplied or was invalid.]
   System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) +368
   System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path) +209
   System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path) +16
   System.Web.Mvc.HtmlHelper.AntiForgeryToken() +10
  <snip>

L’eccezione si verifica su tutti gli utenti collegati; ma facciamo un passo indietro e cerchiamo di capire quali fattori possono determinare un problema di questo genere.

Per prima cosa il problema si riscontra solo su applicazioni che sono state aggiornate alla versione 2 di ASP.NET MVC (quelle nate da questa versione rimangono estranee al problema) e, nello specifico, in una farm in cui non tutte le applicazioni sono state aggiornate -(quindi una situazione ibrida, stessa applicazione ma su alcuni server in MVC1 e su alcuni su MVC2); per complicare la situazione, e nel caso replicarla, è necessario che il balancer in fronte ai server web sia configurato in Round Robin, e che quindi l’utente, ad ogni richiesta, possa esser rimbalzato da un server ad un altro.

Come potete vedere la casistica è molto ristretta, ma la fortuna sicuramente non è dalla mia parte ed ovviamente ci sono incappato in pieno.

In questo post James Crowley spiega nel dettaglio la problematica.

Be careful!
Ciauz


MVC , Exception , Security , Farm

0 comments

ForEach in un IEnumerable<T>

Print Content | More

Linq è senza ombra di dubbio una delle features più belle introdotte da Microsoft in .NET negli ultimi anni (dopo i Generics); sicuramente anche gli Extension Methods hanno il loro fascino agevolando lo sviluppatore nella scrittura del codice. Purtroppo una cosa che mi manca in Linq (ma in realtà è un extension method) è il ForEach per IEnumerable<T>. In effetti c’è la possibilità di utilizzarlo per IList<T> e per le array, ma non per IEnumerable<T>.
Stufo di scrivere il foreach ogni volta, ho deciso di realizzarmi un’extension method che risolvesse il problema :).

Lo snippet seguente mostra la realizzazione:

/// <summary>
/// Eaches the specified enumeration.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="enumeration">The enumeration.</param>
/// <param name="action">The action.</param>
public static void ForEach <T> ( this IEnumerable <T> enumeration , Action <T> action )
{
    Ensure.That ( enumeration ).IsNotNull ( );

    foreach ( T item in enumeration )
        action ( item );
}

Il suo UnitTest (sempre utilizzando SharpTestEx):

[TestMethod]
public void eachTest_with_null_object_shold_throw_argumentNullException()
{
    var mockService = MockRepository.GenerateStrictMock<IFakeClass>();
    ActionAssert.Throws<ArgumentNullException>(() => ((IEnumerable<string>)null).ForEach(x => mockService.FakeMethod("testValue")));
}

[TestMethod]
public void eachTest_with_valid_object()
{
    IEnumerable<string> values = new List<string> { "testValue1", "testValue2", "testValue3" };

    var mockService = MockRepository.GenerateStub <IFakeClass>();

    values.ForEach(mockService.FakeMethod);

    var calls = mockService.GetArgumentsForCallsMadeOn(obj => obj.FakeMethod(null));

    calls [ 0 ] [ 0 ].Should ( ).Be.EqualTo ( "testValue1" );
    calls [ 1 ] [ 0 ].Should ( ).Be.EqualTo ( "testValue2" );
    calls [ 2 ] [ 0 ].Should ( ).Be.EqualTo ( "testValue3" );
}

 

Ciauz


C# , Linq , Extension Methods

4 comments