2017-05-02 3 views
1

Avertissement: Je suis un nouveau modèle de Moq, de test unitaire avec Moq et de TDD en général.Comment tester un contrôleur MVC avec trois dépendances à l'aide du Moq

J'ai un contrôleur avec trois dépendances. Voici le Constructor (etc) au SomethingController:

public class SomethingController : Controller 
    { 
     private readonly ILogger<SomethingController> _logger; 
     private readonly ISomethingRepository _something; 
     private readonly IExceptionSvc _ex; 

     public SomethingController(ILogger<SomethingController> logger, 
      ISomethingRepository something, 
      IExceptionSvc ex) 
     {    
      _logger = logger; 
      _something = something; 
      _ex = ex; 

     } 

[HttpGet] 
     [AllowAnonymous] 
     public JsonResult GetStuff() 
     { 
      //intitialize list 
      var stuffs = new List<StuffViewModel>(); 

     try 
     { 
      _logger.LogInformation("SomethingController: GetStuff() - Getting Stuff, sorted ascending."); 

      //get the stuffs 
      stuffs = _something.GetStuff(); 

      _logger.LogInformation("Retrieved {0} Stuffs.", stuffs.Count); 
     } 
     catch (Exception ex) 
     { 
      _logger.LogError("Error in SomethingController: GetStuff()", ex); 
      return _ex.Http500ErrorReturn("GetStuff"); 
     } 

     return Json(stuffs); 
    } 

} 

Maintenant, est ici la description de ce que chaque dépendance est pour:

ILogger: Ceci est simplement pour l'enregistrement, en utilisant Microsoft.Extensions. Connexion via NLog. ISomethingRepository: Cela fait tout le travail (enfin ... l'implémentation, vraiment). Il appelle la base de données et obtient des choses. Il existe une méthode appelée GetStuff(), qui renvoie simplement une liste de Stuffs. Ce référentiel a une dépendance sur la base de données, qui est injectée dans le repo via le constructeur.
IExceptionSvc: Ceci est juste un petit service stupide qui a une méthode qui renvoie une réponse 500 Erreur pour un retour au format JSON à l'appelant.

Je veux tester l'action GetStuff() dans le contrôleur, qui appellera l'implémentation GetStuff() dans le référentiel.

J'ai actuellement le code suivant dans bouchonné, dans mon projet de test:

public void GetStuff_Is_Awesome() 
     { 
      Mock<ILogger<SomethingController>> logger = new Mock<ILogger<SomethingController>>(); 
      Mock<ISomethingRepository> something = new Mock<ISomethingRepository>(); 
      Mock <IExceptionSvc> ex = new Mock<IExceptionSvc>(); 
      SomethingController sc = new SomethingController(logger.Object, something.Object, ex.Object); 

sc.GetStuff(); 

//...what now? What am I looking for? Am I going to see a list of stuffs here? 

} 

Je veux juste savoir à quoi vous attendre? Est-ce que je teste si une liste de Stuffs a été retournée? Comment puis-je tester cela?

Voici la mise en œuvre de GetStuff() dans le référentiel (avec le constructeur repo pour l'amour de référence):

private readonly ApplicationDbContext _context; 
     private readonly ILogger<SomethingRepository> _logger; 

     public SomethingRepository(ApplicationDbContext context, 
      ILogger<SomethingRepository> logger) 
     { 
      _context = context; 
      _logger = logger; 
     } 

public List<StuffViewModel> GetStuff() 
     { 
      List<StuffViewModel> stuffs = null; 
      stuffs = _context.Stuffs.OrderBy(b => b.Name).Select(b => new StuffViewModel 
       { 
        Id = b.Id, 
        Name = b.Name 
       }).ToList(); 

return stuffs; 
      } 
+0

Pouvez-vous me donner un exemple? – crackedcornjimmy

+0

J'ai ajouté l'implémentation GetStuff() maintenant. – crackedcornjimmy

+0

En supposant que 'GetStuff' est une action, le retour sera un' ActionResult'. Vous devrez ensuite inspecter cette valeur de retour pour affirmer diverses choses que vous souhaitez tester à ce sujet. –

Répondre

3

Pensez comme Arranger, Loi Assertion

public void GetStuff_Is_Awesome() 
{ 
    //arrange 
    Mock<ILogger<SomethingController>> logger = new Mock<ILogger<SomethingController>>(); 
    Mock<ISomethingRepository> something = new Mock<ISomethingRepository>(); 
    Mock <IExceptionSvc> ex = new Mock<IExceptionSvc>(); 
    SomethingController sc = new SomethingController(logger.Object, something.Object, ex.Object); 

    //act 
    sc.GetStuff(); 

    //assert 
} 

Ainsi, vous vouloir affirment que quelque chose est arrivé, ou quelque chose a été appelé.

Sans en savoir plus sur votre domaine, ou le ISomethingRepository, vous pourrait Assertion que la méthode a été appelée:

something.Verify(m => m.MethodToCheckIfCalled()); 

D'autres options seraient à configurer les valeurs de retour pour MethodToCheckIfCalled et faire valoir les résultats, etc. ..

en supposant une méthode GetStuff sur votre contrôleur qui ressemble à:

public ActionResult GetStuff() 
{ 
    var data = _something.GetFromRepo(); 
    return View(data); 
} 

Je voudrais faire quelque chose comme:

public void GetStuff_Is_Awesome() //please don't call it this 
{ 
    //arrange 
    Mock<ILogger<SomethingController>> logger = new Mock<ILogger<SomethingController>>(); 
    Mock<ISomethingRepository> something = new Mock<ISomethingRepository>(); 
    Mock <IExceptionSvc> ex = new Mock<IExceptionSvc>(); 
    SomethingController sc = new SomethingController(logger.Object, something.Object, ex.Object); 

    //setup your something mock GetFromRepo method to return a List of StuffViewModel 
    something.Setup(m=> m.GetFromRepo()) 
     .Returns(new List<StuffViewModel>(){Id = 1, Name = "Test"}); 

    //act 
    var result = sc.GetStuff(); 

    //assert 

    //safely cast result to ViewResult 
    var viewResult = result as ViewResult; 

    Assert.IsNotNull(viewResult); 
    Assert.IsNotNull(viewResult.Model); 

    // add additional checks on the Model.. loads of ways of doing this 
    var viewResultModel = viewResut.Model as List<StuffViewModel>; 

    Assert.AreEqual(1, viewResultModel.First().Id); 
    Assert.AreEqual("Test", viewResultModel.First().Name); 
} 
+0

J'ai ajouté une implémentation de GetStuff(). Cela aide-t-il à la spécificité? – crackedcornjimmy

+1

a édité la réponse avec l'exemple – Alex

+0

J'ai fait quelque chose comme votre réponse et je vois un peu de lumière ici. Le seul élément qui me parvient, cependant, est que le test ne touche pas réellement la base de données. Ainsi, aucune donnée ne sera jamais retournée. Est-ce prévu? – crackedcornjimmy