2016-06-01 17 views
7

Ho provato a farlo e ho effettuato molte ricerche su google/stackoverflow senza fortuna.ModelState.IsValid sempre true durante il test del controller in Asp.Net MVC Web Api

Ho un semplice modello:

public class MovieModel 
{ 
    public string Id { get; set; } 

    [Required] 
    [StringLength(100)] 
    public string Name { get; set; } 
} 

Metodo nel controller:

// POST: api/Movies 
public IHttpActionResult Post([FromBody]MovieModel movieModel) 
{ 
    if (ModelState.IsValid) 
    { 
     //Code 
    } 
} 

E un metodo di prova (è un test di integrazione, ma lo stesso sarebbe accaduto in unit test):

[TestMethod] 
public void MoviesController_Post_Without_Name() 
{ 
    // Arrange 
    var model = new MovieModel(); 
    model.Name = ""; 

    // Act 
    var result = controller.Post(model); 

    // Assert 
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult)); 
    Assert.AreEqual(6, controller.Get().Count()); 
} 

Nonostante il modello sia chiaramente non valido, valuta sempre la proprietà IsValid su true.

Ho provato molti approcci finora senza successo.

risposta

5

La soluzione probabilmente funziona, ma un modo migliore è utilizzare il metodo ApiController.Validate.

public void MoviesController_Post_Without_Name() 
{ 
    // Arrange 
    var model = new MovieModel(); 
    model.Name = ""; 

    // Act 
    controller.Validate(model); //<---- use the built-in method 
    var result = controller.Post(model); 

    // Assert 
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult)); 
    Assert.AreEqual(6, controller.Get().Count()); 
} 
+0

Ho provato questo metodo .Validate prima, ma non esiste. Sto usando MVC 5. –

+0

Il riferimento Microsoft mostra il metodo Validate, per la versione 5 di MVC, ma semplicemente non funziona, né Intellisense né build funzionano. –

+0

@ AndréBaptista Perché parli di MVC? 'ApiController' è una classe API Web e si trova in' System.Web.Http'. Assicurati di aver aggiunto i pacchetti NuGet corretti al progetto di test. –

4

Grazie alla this sito, ho trovato la soluzione:

private void SimulateValidation(object model) 
{ 
    // mimic the behaviour of the model binder which is responsible for Validating the Model 
    var validationContext = new ValidationContext(model, null, null); 
    var validationResults = new List<ValidationResult>(); 
    Validator.TryValidateObject(model, validationContext, validationResults, true); 
    foreach (var validationResult in validationResults) 
    { 
     this.controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage); 
    } 
} 

compresa una riga nel metodo di prova in questo modo:

public void MoviesController_Post_Without_Name() 
{ 
    // Arrange 
    var model = new MovieModel(); 
    model.Name = ""; 

    // Act 
    SimulateValidation(model); 
    var result = controller.Post(model); 

    // Assert 
    Assert.IsInstanceOfType(result, typeof(InvalidModelStateResult)); 
    Assert.AreEqual(6, controller.Get().Count()); 
} 

Speranza che aiuta qualcuno, mi avrebbe salvato alcune ore a caccia del web.

+0

questo funziona per me, ma non con i modelli annidati – MattjeS

+1

lavorate per core 2.0, per annidati basta fare 'SimulateValidation (modello); SimulateValidation (model.child); ' – ono2012

+0

Grazie mille @Andre Baptista, questo funziona per me –