2

J'ai un Area sur mon site MVC. Cette zone a la configuration typique Controller/Model/View.Se moquant d'un contrôleur pour tester ViewEngine dans une zone - nullreference et RouteData

En tant que contrôleur je le code suivant:

public class DocumentCreatorController : Controller 
{ 
    // GET: Templates/DocumentCreator 
    public ActionResult OfferTemplate(BaseDocumentViewModel data) 
    { 
     return this.Pdf(nameof(OfferTemplate), data, "File.pdf"); 
    } 
} 

La méthode this.Pdf fait deux ou trois choses, mais l'intéressant est qu'il revient à l'appel ViewEngine:

var viewResult = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName); 

Here I appelez le FindPartialView avec un ControllerContext et un PartialViewName. Mon PartialViewName provient du nameof(OfferTemplate) à partir de l'action du contrôleur OfferTemplate. Je pense que le controllercontext est mon défi.

Mon défi:

Quand je veux mettre cela dans un test unitaire (en utilisant QMC), j'ai le code suivant basé sur des pages telles que Mocking The RouteData Class in System.Web.Routing for MVC applications et Mocking Asp.net-mvc Controller Context:

[TestMethod] 
public void OfferTemplate() 
{ 
    var ctr = SetupControllerWithContext(); 

} 

private static DocumentCreatorController SetupControllerWithContext() 
{ 
    var routeData = new RouteData(); 
    routeData.Values.Add("controller", "DocumentCreatorController"); 
    routeData.Values.Add("action", "OfferTemplate"); 


    var request = new Mock<HttpRequestBase>(); 
    request.Expect(r => r.HttpMethod).Returns("GET"); 
    var mockHttpContext = new Mock<HttpContextBase>(); 
    mockHttpContext.Expect(c => c.Request).Returns(request.Object); 
    var controllerContext = new ControllerContext(mockHttpContext.Object 
     , routeData, new Mock<ControllerBase>().Object); 

    DocumentCreatorController ctr = new DocumentCreatorController(); 
    ctr.ControllerContext = controllerContext; 
    return ctr; 
} 

Ce qui donne l'erreur suivante:

Eesy.Websites.Api.Tests.Controllers.DocumentCreatorControllerTest.OfferTemplate threw exception: System.NullReferenceException: Object reference not set to an instance of an object.

Ceci je ne comprends pas.

Ma configuration du dossier:

enter image description here

image de débogage sur ControllerContext à appeler la FindPartialView:

enter image description here

Quelqu'un a une idée? Est-ce parce que j'ai mal configuré RouteData?

+1

Il faudrait être 'routeData.Values.Add (" controller "," DocumentCreator ");' (pas '" DocumentCreatorController ") –

+1

Vous essayez de simuler et de tester le code du framework. Résumé cette fonctionnalité dans le code que vous contrôlez, vous pouvez donc tester en isolation si nécessaire. Cela semble être un [problème XY] (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Quel est le but ultime que vous essayez d'atteindre? – Nkosi

+0

@Nkosi Bon point. J'essaie de générer automatiquement un PDF (HTML au format PDF) en utilisant un test unitaire, donc je peux vérifier le processus de génération de PDF fonctionne. Et j'espérais pouvoir le faire en utilisant mon contrôleur, mais évidemment, il serait logique de faire un service au lieu d'éviter tout cela :-) –

Répondre

1

Vous essayez de simuler et de tester le code de cadre. Résumé cette fonctionnalité dans le code que vous contrôlez, vous pouvez donc tester en isolation si nécessaire.

Actuellement l'action et par extension le contrôleur est étroitement couplé aux dépendances externes de tiers. Si le but était de tester le flux d'action du contrôleur de manière isolée, il est conseillé d'extraire la génération PDF de la tierce partie afin qu'elle puisse être raillée pour faciliter la testabilité.

public interface IDocumentService { 
    ActionResult ToPdf(Controller arg1, string arg2, object arg3, string arg4); 
} 

Le contrôleur dépend explicitement de cette abstraction via l'injection du constructeur. Donc, maintenant, pour tester le processus de génération de pdf du contrôleur, il vous suffit de simuler votre abstraction.

[TestMethod] 
public void OfferTemplate() { 
    //Arrange  
    var serviceMock = new Mock<IDocumentService>(); 
    //...setup mock for use case 

    var controller = new DocumentCreatorController(serviceMock.Object); 
    var data = new BaseDocumentViewModel { 
     //... 
    }; 

    //Act 
    var actual = controller.OfferTemplate(data); 

    //Assert 
    //...assert behavior 
} 

La mise en œuvre effective du service intégrerait la fonctionnalité réelle et serait enregistrée avec le conteneur d'injection de dépendance avec l'abstraction.

Pour tester la génération actuelle, vous devez effectuer un test d'intégration qui est un autre sujet.