Come tutti sappiamo con l’avvento di .Net Core tutto l’ecosistema sta subendo evoluzioni, fin dalla prima versione del progetto ASP.NET MVC Core è stato scelto come sistema di testing XUnit.

xunit-dot-net-full-logo

Per poter utilizzare XUnit da riga di comando dobbiamo aggiungere il pacchetto nuget “xunit” al nostro progetto.

<ItemGroup>
	<PackageReference Include="xunit" Version="2.2.0" />
</ItemGroup>
  

mentre per poter utilizzare xunit all’interno di Visual Studio  dovremo aggiungere i seguenti pacchetti nuget (in questo articolo eseguiremo i test direttamente da VisualStudio).

<ItemGroup>
	<PackageReference Include="xunit" Version="2.2.0" />
	<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>
  

Con XUnit, quando scriviamo il nostro test, abbiamo la possibilità di scegliere tra 2 differenti tipi di Unit Test, Fact e Theory.

I test di tipo Fact sono i classici test che siamo abituati a vedere,

[Fact] public void MemoryRepository_PersonById_foundValue() { //Arrange var memoryContext = new MemoryRepository(); memoryContext.InsertPerson(new Person() { ID = 1, Code="001", Name="Person One", Role="User" }); memoryContext.InsertPerson(new Person() { ID = 2, Code = "002", Name = "Person Two", Role = "Admin" }); memoryContext.InsertPerson(new Person() { ID = 3, Code = "003", Name = "Person Three", Role = "Owner" }); //Act var person = memoryContext.PersonById(1); //Assert Assert.NotNull(person); Assert.Equal("Person One", person.Name); }

L’esempio sopra, testa della classe MemoryRepository il metodo PersonById che deve filtrare per id.

Andiamo ad analizzare nel dettaglio il test, così come siamo stati abituati nel tempo possiamo vedere la sezione Arrange dove  andiamo ad inizializzare tutte le classi che utilizzeremo nel test; la sezione di Act dove eseguiremo i metodi oggetto del test ed in fine la sezione di Assert dove andremo ad eseguire i controlli del corretto risultato del test, che nel nostro caso non deve essere null ed il nome deve essere “Person One”.

Per poter eseguire i test all’interno di Visual Studio dobbiamo per prima cosa compilare il progetto in modo che tutte le classi di test siano compilate a questo punto aprendo la vista Test Explorer possiamo vedere tutti i test che possiamo avviare.

TestExplorerWindow

Individuato all’interno della lista il test che vogliamo eseguire facciamo click destro e selezioniamo “Run Selected Test” (ovviamente se la nostra necessità è quella di avviare il test come debug per verificare eventuali bug, possiamo avviare il test selezionando la voce “Debug Selected Test”).

RunTest

Al termine del test possiamo vedere il risultato

TestCompleted

Ovviamente il test eseguito è molto semplice ed xunit mette a disposizione tutta una serie di features molto interessanti; ad esempio per testare se una determinata eccezione viene avviata possiamo fare in questo modo

[Fact] public void ResponseToFileAttributeResponse_onExecuted_PathSpecified()

{ //Arrange var attribute = createAttribute("txt", "FILENAME", false, false, Path.GetTempPath()); var context = createBatchExecutionContext(Guid.NewGuid(), new byte[] { 123, 221, 213, 128, 165 }); //Act var ex = Record.Exception(() => attribute.onExecuted(context)); //Assert Assert.Null(ex); }

Testando la variabile ex siamo in grado di capire se l’eccezione è stata lanciata.

Ipotizziamo che il nostro test prevede dei valori di input, così come visto fin’ora dovremmo create tanti metodi di test [Fact] quante sono le combinazioni da testare.
XUnit ci mette a disposizione l’attributo [Theory], quando marchiamo un test come theory stiamo dicendo ad XUnit che questo test prevede dei dati di input che andremo a specificare utilizzando 1 o più attributi [InlineData], di seguito un esempio.

[Theory]
[InlineData("txt", "FILENAME",false, false, "", "FILENAME.txt", "ce8a738b-2534-4060-9f1c-9da6eba4aef8")]
[InlineData("txt", "FILENAME", true, false, "", "FILENAME-ce8a738b-2534-4060-9f1c-9da6eba4aef8.txt", "ce8a738b-2534-4060-9f1c-9da6eba4aef8")]
public void ResponseToFileAttributeResponse_FullFileName(string fileExtention, string fileName, bool sessionIdInFileName, bool timeStampToken,  string path, string expected, string sessionId)
{
        //Arrange
        var attribute = createAttribute(
fileExtention, fileName, sessionIdInFileName,
timeStampToken, path);
var context = createBatchExecutionContext(
new Guid(sessionId), "TEST TEST TEST"); //Act attribute.onExecuted(context); //Assert Assert.Equal(expected, attribute.FullFileName); }

Così facendo XUnit eseguira N volte il test, dove N sono le [inlineData] che sono state configurate. Questo ci permette di scrivere dei test configurabili scrivendo test piu generici basati su dei parametri.

Andiamo ora a fare un esempio che sicuramente si accosta di più al mondo reale, ipotizziamo di avere se suguenti classi :

Una classe repository di accesso ai dati che implementa la seguente interfaccia

public interface IDataRepository
{
    List<Person> AllPersons();
    Person PersonById(int id);
    List<Person> PersonByCode(string code);
    List<Person> PersonByRole(string role);
    bool InsertPerson(Person person);
    bool UpdatePerson(Person person);
    bool RemovePerson(Person person);
}
  

Una classe Provider di generazione degli accorpamenti dei dati

public class StatisticsProvider
{
    private IDataRepository _dataRepository = null;
    public StatisticsProvider(IDataRepository dataRepository)
    {
        _dataRepository = dataRepository;
    }

    public List<StstisticsByRoleModel> ByRole()
    {
        var result = (from d in _dataRepository.AllPersons()
                        group d by d.Role into grp
                        select new StstisticsByRoleModel()
                        {
                            Role = grp.Key,
                            Count = grp.Count()
                        }
            ).ToList();

        return result;
    }
}
  

alla quale passiamo la nostra classe Repository di accesso ai dati utilizzando la dependency injection.

Come possiamo testare il corretto funzionamento della classe StatisticsProvider ?

Semplice, moqando la classe repository; per fare questo possiamo utilizzare una libreria chiamata Moq che possiamo includere direttamente da Nuget.

Moq e in grado di definire un interfaccia in modo da restituire dei dati prefissati (appunto moqati) come risposta di un metodo, ecco come

var dataRepository = new Mock<IDataRepository>(MockBehavior.Strict);
dataRepository.Setup(s => s.AllPersons())
        .Returns(Persons)
        .Verifiable();

  

In queste righe di codice stiamo configurando Moq in modo che

  • Implementa ll tipo IDataRepository (la nostra interfaccia del data repository),
  • Alla chiamata del metodo AllPersons() rispondere con il contenuto della variabile Persons.
  • Deve essere verificato che la chiamata al metodo AllPersons() sia eseguita

A questo punto continuiamo inizializzando la nostra classe StatisticsProvider alla quale andiamo a passare nel costruttore l’implementazione moqata dell’interfaccia IDataRepository

var statProvider = new StatisticsProvider(dataRepository.Object);
  

quindi il nostro testo completo sarà così fatto

[Fact]
public void StatisticsProviderTest_ByRole()
{
    //Arrange
    var Persons = new List<Person>()
    {
        new Person()
        {
            ID=1, Code="001", Name="Person One", Role="User"
        },
        new Person()
        {
            ID=2, Code="002", Name="Person Two", Role="Admin"
        }
    };

    var dataRepository = new Mock<IDataRepository>(MockBehavior.Strict);
    dataRepository.Setup(s => s.AllPersons())
        .Returns(Persons)
        .Verifiable();

    var statProvider = new StatisticsProvider(dataRepository.Object);

    //Act
    var response = statProvider.ByRole();

    //Assert
    Assert.NotNull(response);
    Assert.Equal(2, response.Count);
    Assert.Collection(response,
        e1 =>
        {
            Assert.Equal("User", e1.Role);
            Assert.Equal(1, e1.Count);
        },
        e2 =>
        {
            Assert.Equal("Admin", e2.Role);
            Assert.Equal(1, e2.Count);
        });

    var ex = Record.Exception(() => dataRepository.Verify());
    Assert.Null(ex);
}

come si puo notare nella sezione Assert viene eseguito il metodo Verify() della classe moqata. Questo metodo implementato da moq controlla che tutti i setup configurati come Verifiable siano stati chiamati, in caso contrario si genera un’eccezione; nel nostro caso viene verificato che sia chiamato il metodo AllPersons().

In questo articolo abbiamo visto come implementare test utilizzando xUnit e Moq, sperando che sia stata una lettura piacevole  vi do appuntamento con il prossimo articolo dove continueremo ad approfondire le novità dell’ecosistema .Net Core.

Happy Coding.


DependencyInjectionIn questo articolo parleremo della Dependency Injection, un pattern che consente di creare applicazioni flessibili e semplifica la fase di unit test.

Quando si approccia per la prima volta alla dependency injection può risultare un po' ostico da capire ed inizialmente si ha l’impressione che questo pattern rallenti la scrittura del codice, ma così non è !

La dependency injection facilita la creazione di componenti detti “debolmente accoppiati”. Per componenti debolmente accoppiati si intende quando utilizziamo un componente del quale conosciamo i metodi e le proprietà ma non conosciamo la sua implementazione.

Uno dei grandi vantaggi nell’utilizzo della dependency injection è che siamo portati a dover scrivere dei componenti o classi che saranno poi facilmente testabili in fase di unit test.

Vediamo ora come poter scrivere il codice per utilizzare al meglio la dependency injection.

Ipotizziamo di dover scrivere del codice per inviare una email, avremo una classe provider con i metodi necessari per gestire l’invio, ma  non sapendo quale server utilizzare (OWA o smtp), come possiamo scrivere il nostro codice senza avere tutte le informazioni?
Possiamo iniziare definendo l’interfaccia del nostro provider in questo modo
    public interface IEMailProvider
    {
        bool SendEMail(List<string> to, List<string> cc, string subject, string body);
    }
  

Ora conosciamo il metodo con i parametri che dobbiamo invocare per inviare la mail. Procediamo creando la nostra classe Helper che utilizza l’interfaccia sopra definita per l’invio della mail.

    public class EMailHelper
    {
        IEMailProvider _emailProvider;
       
        public bool SendEMail(List<string> to, List<string> cc, string subject, string body)
        {
            return _emailProvider.SendEMail(to, cc, subject, body);
        }
    }
  

A questo punto dobbiamo fare in modo che chi utilizza la classe helper possa passare l’implementazione dell’interfaccia  IEmailProvider , il metodo più utilizzato è quello di dare la possibilità di passare l’implementazione tramite il costruttore, in questo modo:

    public class EMailHelper
    {
        IEMailProvider _emailProvider;
        public EMailHelper(IEMailProvider emailProvider)
        {
            _emailProvider = emailProvider;
        }

        public bool SendEMail(List<string> to, List<string> cc, string subject, string body)
        {
            return _emailProvider.SendEMail(to, cc, subject, body);
        }
    }
  

Quando l’implementazione della classe viene passato nel costruttore stiamo parlando di “Constructor Injection”, in alternativa possiamo utilizzate il “Method Injection” dove l’implementazione viene passata direttamente al metodo che stiamo per eseguire.

Ora siamo in grado di poter chiamare la nostra classe helper specificando quale deve essere il provider da utilizzare, che nel nostro caso sarà un provider per OWA

    [HttpPost]
    public bool SendEMail(List<string> to, List<string> cc, string subject, string body)
    {
        var emailHelper = new EMailHelper(new OWAEmailProvider());
        return emailHelper.SendEMail(to, cc, subject, body);
    }
  

Naturalmente la nostra classe OWAEmailProvider deve implementare l’interfaccia IEMailProvider

public class OWAEmailProvider : IEMailProvider { public bool SendEMail(List<string> to, List<string> cc, string subject, string body) { . . . . . . . } }

Tutto quello che abbiamo visto fino ad ora è molto interessante, ma quello che risalta subito all’occhio è che alla fine deve esserci un componente che è a conoscenza di questo legame tra Interfaccia e la sua implementazione, questa informazione è configurata all’interno di un “Contenitore” ,detto anche IoC Container (IoC è l’acronimo di Inversion Of Controll) o Dependency Injection Container.

Il container ha una duplice funzione; la prima quella di mettere a disposizione l’associazione Interfaccia/Classe tramite dei metodi di ricerca, la seconda quella di Activator  delle classi in modo da poter gestire Constructor Injection per tutte quelle classi che sono presenti nel container (da qui Inversion Of Controll ‘istanziazione delle classi la esegue direttamente il container non la classe utilizzatrice).

Andiamo a vedere nel dettaglio l’implementazione della dependency Injection all’interno di ASP.NET Core.

In ASP.NET Core tutte le classi registrate nel IoC Container vengono chiamate servizi.

Nel momento in cui decido di registrare una servizio all’interno del IoC dobbiamo decidere il LifeTime con cui lo andremo ad utilizzare, le opzioni che abbiamo a disposizione sono:

  • Singleton
    Il servizio viene creato la prima volta che viene chiamato e tutte le richieste successive viene utilizzata la stessa istanza
  • Transient
    Il servizio viene creato ad ogni chiamata
  • Scoped
    Il servizio viene creato ad ogni chiamata, ma l’istanza è condivisa all’interno della stessa request

Per configurare i servizi all’interno dell’IoC Container dobbiamo eseguire la configurazione nella classe StartUp del progetto e più nel dettaglio nel metodo ConfigureService, che nel nostro caso sarà:

public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc();

services.AddSingleton<IEMailProvider, OWAEmailProvider>(); }

L’implementazione della Dependency Injection di Microsoft è integrata nell ASP.NET Mvc Core Framework, e la maggior parte degli oggetti del MVC vengono attivati dal container, questo ci permette di poter utilizzare sia il Constructor Injection sia il Method Injection direttamente sul Controller, TagHelper, Middleware ed altri oggetti.

Una volta registrato il provider per l’invio email possiamo modificare il nostro controller in questo modo

    public class EMailController : Controller
    {
        IEMailProvider _emailProvider;

        public EMailController(IEMailProvider emailProvider)
        {
            _emailProvider = emailProvider;
        }

        [HttpPost]
        public bool SendEMail(List<string> to, List<string> cc, string subject, string body)
        {
            return _emailProvider.SendEMail(to, cc, subject, body);
        }

    }
  

Fino ad ora abbiamo visto esempi di constructor injection, ma abbiamo detto che l’IoC Container ti permette di ricercare direttamente i servizi.

Per poter accedere direttamente all’IoC Container nella classe HTTPContext è presente la proprietà RequestService di tipo IServiceProvider ,di seguito un esempio di come utilizzarla:

[Route("api/EMail")]
public class EMailController : Controller { [HttpPost] public bool SendEmail(List<string> to, List<string> cc, string subject, string body) { IEMailProvider emailProvider = (IEMailProvider)this.HttpContext.RequestServices.GetService(typeof(IEMailProvider)); return emailProvider.SendEMail(to, cc, subject, body); } }

Attualmente oltre all’implementazione Microsoft di Dependency Injection è possibile utilizzare anche altri framework come AUTOFAC o Ninject, su internet si trova la documentazione necessaria per configurare il framework preferito senza grandi interventi.

In questo articolo abbiamo parlato del pattern Dependency Injection ed abbiamo visto tramite un esempio pratico come implementarlo in ASP.NET MVC Core.

Vi aspetto per il prossimo articolo dove vedremo come la Dependency Injection ci aiuta nel costruire componenti facilmente testabili e come usare XUnit e Moq per scrivere i nostri unit test.

Happy coding !!!


Nel precedente articolo intitolato ASP.NET Core Middleware abbiamo parlato di cosa sono i middleware ed abbiamo visto come usare i middleware buit-in di Microsoft.

Ora vediamo come implementare un semplice custom Middleware che dovrà gestire una blacklist di pagine, se la pagina richiesta si trova all’interno dell’elenco si dovra rispospondere con uno status 404 (page not found).

Per prima cosa creiamo un progetto .Net Core di tipo Class Library

NewProject

ed andiamo ad aggiungere una classe che andiamo a nominare BlackListMiddleware.

La classe BlackListMiddleware sarà il nostro middleware.

NewClass

Andiamo ad aggiungere il costruttore alla classe appena creata, il costruttore avrà un parametro che chiameremo next di tipo RequestDelegate che verrà iniettato con una dependency injection direttamente da Asp.Net, il parametro next è il puntatore al prossimo middleware della pipeline da eseguire.

    public class BlackListMiddleware
    {
        RequestDelegate _next;
        public BlackListMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    }
  

Per poter essere invocato il nostro middleware deve esporre un metodo che dobbiamo chiamare Invoke, nel quale andiamo ad implementare la logica di business.

        public async Task Invoke(HttpContext context)
        {
            var urlToCheck = context.Request.Path;
            if (_urlBlackList.Any(p => urlToCheck.StartsWithSegments(p)))
            {
                context.Response.StatusCode = 404;
            }
            else
            {
                await this._next.Invoke(context);
            }
        }
  

Essendo un progetto dimostrativo la logica di gestione degli indirizzi è semplifcato al massimo e gestito con una lista di stringhe statiche denominato urlToCheck.

Terminata la scrittura del metodo invoke dobbiamo inserire il middleware appena scritto all’interno della pipeline di ASP.NET Core. Procediamo aggiungendo alla nostra soluzione un progetto ASP.NET MVC Core, utilizzando il template di default , che chiameremo BlackListMiddleware.Web.

NewProjectWeb

Per inserire il nostro middleware all’interno della pipeline del nuovo progetto web creato dobbiamo modificare la classe di Startup, del progetto BlackListMiddleware.Web, in questo modo

        public void Configure(IApplicationBuilder app)
        {
            app.UseMiddleware<BlackListMiddleware>();
            app.UseStaticFiles();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
  

A questo punto non ci resta che fare un test, compiliamo ed avviamo la soluzione; selezionando la voce about dal menu dell’applicazione avviata mi aspetto che la risposta sia “404 Page not found”. Il nostro middleware ha fatto il suo lavoro.

Il middleware ora è pronto ad essere utilizzato, possiamo pubblicarlo su nuget e renderlo pubblico, ma prima dobbiamo fare una piccola modifica.

E’ buona prassi creare un’extention alla classe IApplicationBuilder che si occuperà di registrare il nostro middleware all’interno della pipeline, di seguito un esempio:

    public static class BlackListMiddlewareBuilderExtention
    {
        public static IApplicationBuilder UseBlackList(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<BlackListMiddleware>();
        }
    }
  

così la nostra classe di startup diventa:

        public void Configure(IApplicationBuilder app)
        {
            app.UseBlackList();
            app.UseStaticFiles();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
       
  

Ed eccoci giunti al termine il nostro middleware ora e pronto ad essere pubblicato su nuget per la distribuzione, potete trovare il codice sorgente di questo articolo nel mio repository GitHub qui.

Non mi resta che salutarvi ed augurarvi buon divertimento alla scoperta dei middleware e…….

happy coding !!!


"Middleware are software components that are assembled into an application pipeline to handle requests and responses. Each component chooses whether to pass the request on to the next component in the pipeline, and can perform certain actions before and after the next component is invoked in the pipeline. Request delegates are used to build the request pipeline. The request delegates handle each HTTP request."

Questa la definizione ufficiale di Microsoft di cosa è un middleware.

A prima vista la definizione non ci colpisce perchè ha un'aria di cosa già vista, e di fatto non siamo molto lontani dalla realtà, il concetto di middleware non è un concetto nuovo, l'abbiamo già visto in quello che conosciamo come handler http ( i quali si inserivano all'interno della pipeline di esecuzione di ASP.NET).

request-delegate-pipeline

Cosa è cambiato di fatto e perchè si parla così forte di middleware?

Essendo cambiato profondamente Asp.Net con la nuova implementazione Asp.Net Core e non essendo più quel sistema monolitico che era in passato, quale poteva essere il miglior modo di rendere modulare lo sviluppo di applicazioni? La risposta è utilizzando i middleware. Asp.Net Core è un insieme di moduli ed ogni modulo è un middleware che si inserisce all'interno della pipeline di esecuzione delle richieste HTTP di Asp.Net.

Il concetto funzionale del middleware è semplice, prende in input una richiesta HTTP ed esegue il codice per il quale è stato creato, a questo punto o restituisce una risposta HTTP, interrompendo la catena di esecuzione, oppure eseguire il middleware successivo della pipeline.

Possiamo catalogare i middleware in 4 differenti tipologie,

  • Response editing : interviene direttamente sul contenuto della risposta.
  • Request editing : il middleware di tipo  Request-Editing interviene direttamente sulla request ed esegue il prossimo middleware della catena
  • Short-Circuiting : il middleware di tipo Short Circuiting  interviene sulla risposta impostando lo stato ( 404, 403 ) ed interrompendo la catena di esecuzione dei middleware
  • Content : il middleware di tipo content interviene direttamente sulla risposta restituendo un contenuto ed interrompe la catena di esecuzione dei middleware

      MiddlewareType

      La suddivisione identificata è solo una suddivisione logica, nel momento in cui andiamo ad implementare il nostro middleware non dobbiamo necessariamente scegliere quale tipo implementare in quanto non impatta sulla scrittura del codice.

      Attualmente microsoft ha implementato e rilasciato già un set di built-in middleware che sono scaricabili tramite NuGet, di seguito l’elenco :

      • Autentication:
        Supporto per autenticazione
      • Cors:
        Configura Cross-Origin-Resource-Sharing
      • Response Caching:
        Supporto per le risposte da cache
      • Response Compression:
        Supporto per la risposta compressa
      • Routing:
        Gestione del routing
      • Session:
        Gestione della session
      • Static File:
        Supporto per la gestione dei file statici e del directory browsing
      • UrlRewrite:
        Supporto per il rewrite Urls e redirect request

      Ora che abbiamo capito come funzionano i Middleware, andiamo a vedere come possiamo configurare la pipeline, e come specificare un ordine di esecuzione.

      I middleware, come la maggior parte dei componenti che andiamo ad utilizzare all’interno delle nostre applicazioni Net Core, vengono configurati all’interno del metodo Configure della classe “Startup”.

      public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
              {
                  loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                  loggerFactory.AddDebug();
      
                  app.UseApplicationInsightsRequestTelemetry();
      
                  if (env.IsDevelopment())
                  {
      Technorati Tags:
      app.UseDeveloperExceptionPage(); app.UseBrowserLink(); }
      else { app.UseExceptionHandler("/Home/Error"); } app.UseApplicationInsightsExceptionTelemetry(); app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
       

      Come possiamo vedere dall’esempio i middleware che la nostra applicazione utilizza sono diversi. In questo caso il primo middleware ad essere eseguito sarà UseApplicationInsightsRequestTelemetry, e l’ultimo della pipeline sarà UseMvc.

      E' possibile inserire delle condizioni per la manipolazione della pipeline, nel nostro caso se ci troviamo in ambiente di Development verranno inseriti nella pipeline UseDeveloperExceptionPage e UseBrowserLink, altrimenti verrà utilizzato UseExceptionHandler. Possiamo concludere dicendo che i middleware devono essere configurati all’interno della classe di Startup e l’ordine in cui vengono inseriti è esattamente l’ordine che viene utilizzato nell’esecuzione.

      Ora che abbiamo le basi per configurare i Middleware built-in di microsoft, non perdetevi il prossimo articolo dove vedremo, con un esempio pratico, come scrivere un middleware personalizzato.


      Calendar

      <<  December 2017  >>
      MonTueWedThuFriSatSun
      27282930123
      45678910
      11121314151617
      18192021222324
      25262728293031
      1234567

      View posts in large calendar

      Category list