2015-12-02 1 views
17

mi piacerebbe provare questo controller:Unit testing Asp.Net WebAPI: come testare corretto instradamento di un metodo con [FromUri] parametri

[HttpGet] 
public IList<Notification> GetNotificationsByCustomerAndId([FromUri] string[] name, [FromUri] int[] lastNotificationID)   
{ 
    return _storage.GetNotifications(name, lastNotificationID, _topX); 
} 

In particolare, in questo metodo voglio provare che l'array passato in input per formare l'Url della richiesta, è lo stesso array che va in routeData.Values. Se per i parametri a valore singolo (non gli array) funziona, ma non funziona per gli array. Se eseguo il debug di Values, vedo solo controller e action.

[TestMethod] 
public void GetNotificationsByCustomerAndId_ArrayOverload_Should_Match_InputParameter_name() 
{ 
    string[] _testName = new string[] { _testCustomer, _testCustomerBis }; 

    string Url = string.Format(
      "http://www.testpincopallo.it/Notifications/GetByCustomerAndLastID/customersNotificationsInfos?name={0}&name={1}&lastNotificationID={2}&lastNotificationID={3}", 
      _testName[0], _testName[1], 
      _testNotificationID, _testNotificationIDBis); 

    IHttpRouteData routeData = GetRouteData(Url); 
    routeData.Values["name"].Should().Be(_testName); 
} 

C'è un altro modo per eseguire il test dell'unità mentre si stanno passando gli array?

+1

Credo non ci sia modo di testare "Unità", invece si potrebbe fare test di integrazione per HttpServer in memoria per i propri metodi /. Sembrerà chiamare i tuoi metodi usando il client http con i parametri di Query/POST Payload e confrontando il risultato che arriva dal server con quello che ti aspetti. –

risposta

3

Forse è possibile utilizzare List<string> anziché string[] come in this answer?

Inoltre, potrebbe essere necessario inserire name[] anziché name nella stringa di query.

Modifica
Dopo aver guardato in questo, mi chiedo se legame di tipi non semplice modello non è fatto durante la chiamata GetRouteData - dopo tutto, il routing non prende in considerazione questo tipo e non è possibile creare due percorsi che differiscono per es. il numero di elementi nell'array passato.

Quindi è necessario esaminare il binding del modello anziché il routing della richiesta. Per testare il codice senza eseguire effettivamente la chiamata, è possibile recuperare manualmente un oggetto ModelBinder e utilizzarlo per analizzare l'URL. This test from the ASP.NET source code might be relevant for you.

+1

Secondo http://stackoverflow.com/questions/9508265/how-do-i-accept-an-array-as-an-asp-net-mvc-controller-action-parameter .NET si aspetta array senza parentesi o con parentesi indice - '? name = first & name = last' o' name [0] = first & name [1] = last' corrisponde all'argomento Action 'string [] name', ma sono stato confuso da questo prima. Solo per citare, penso che PHP preferisca "? Name [] = first & name [] = last'. – drzaus

+0

@ Martin Ho rifatto il mio codice per testarlo con la tua soluzione, ma non funziona. Il problema è lo stesso: routeData.Values ​​non contiene alcuna informazione sui parametri. –

+0

Hai provato a impostare un punto di interruzione e poi a fare la richiesta dal tuo browser? Potrebbe essere dovuto a un problema in "GetRouteData". –

1

Penso che dovresti creare un nuovo metodo che determinerà automaticamente il numero di elementi dell'array e li esporrà all'URL.

private static void ParameterSubstitution(string[] testName, string[] testNotification, ref string url) 
{ 
    const string firstParametrName = "name"; 
    const string secondParametrName = "lastNotificationID"; 
    // first parametr 
    url += string.Format("?{0}={1}", firstParametrName, string.Join(string.Format("&{0}=", firstParametrName), testName)); 
    // second parametr 
    url += string.Format("&{0}={1}", secondParametrName, string.Join(string.Format("&{0}=",secondParametrName), testNotification)); 
} 

e quindi è possibile utilizzarlo come:

var testName = new[] { "Name1", "Name2"}; 
var testNotification = new[] { "Notification1", "Notification2", "Notification3" }; 

var Url = 
    @"http://www.testpincopallo.it/Notifications/GetByCustomerAndLastID/customersNotificationsInfos"; 

ParameterSubstitution(testName, testNotification, ref Url); 
1

È possibile creare elenco di parametri di stringa di query per gli elementi dell'array e poi unirsi a loro utilizzando il metodo String.Join con & come separatore. Questo dovrebbe ottenere facilmente la stringa di query richiesta.

[TestMethod] 
     public void GetNotificationsByCustomerAndId_ArrayOverload_Should_Match_InputParameter_name() 
     { 
      string[] _testName = new string[] { _testCustomer, _testCustomerBis }; 

      // ASSUMING _testNotificationIDBis IS STRING ARRAY 
      List<string> nParams = _testName.Select(n => string.Format("lastNotificationID={0}", n)).ToList<string>(); 
      string Url = string.Format(
       "http://www.testpincopallo.it/Notifications/GetByCustomerAndLastID/customersNotificationsInfos?name={0}&name={1}&{2}", 
       _testName[0], _testName[1], 
       String.Join("&", nParams.ToArray())); 

      IHttpRouteData routeData = GetRouteData(Url); 
      routeData.Values["name"].Should().Be(_testName); 
     }