J'ai lu certaines des réponses ici concernant le test des vues et des contrôleurs, et le mocking, mais je n'arrive toujours pas à comprendre comment tester un contrôleur ASP.NET MVC qui lit et définit les valeurs de session (ou toute autre variable basée sur le contexte). Comment fournir un contexte (de session) à mes méthodes de test ? Le mocking est-il la solution ? Quelqu'un a des exemples ? En gros, j'aimerais simuler une session avant d'appeler la méthode du contrôleur et faire en sorte que le contrôleur utilise cette session. Des idées ?
Réponses
Trop de publicités?Consultez le billet de Stephen Walther sur la simulation du contexte du contrôleur :
Conseil ASP.NET MVC n° 12 - Simuler le contexte du contrôleur
[TestMethod]
public void TestSessionState()
{
// Create controller
var controller = new HomeController();
// Create fake Controller Context
var sessionItems = new SessionStateItemCollection();
sessionItems["item1"] = "wow!";
controller.ControllerContext = new FakeControllerContext(controller, sessionItems);
var result = controller.TestSession() as ViewResult;
// Assert
Assert.AreEqual("wow!", result.ViewData["item1"]);
// Assert
Assert.AreEqual("cool!", controller.HttpContext.Session["item2"]);
}
Le cadre ASP.NET MVC n'est pas très convivial pour les simulateurs (ou plutôt, il nécessite trop de configuration pour simuler correctement, et cause trop de frictions lors des tests, IMHO) en raison de son utilisation de classes de base abstraites au lieu d'interfaces. Nous avons eu de la chance en écrivant des abstractions pour le stockage par requête et par session. Nous gardons ces abstractions très légères et ensuite nos contrôleurs dépendent de ces abstractions pour le stockage par requête ou par session.
Par exemple, voici comment nous gérons les formulaires d'authentification. Nous avons un ISecurityContext :
public interface ISecurityContext
{
bool IsAuthenticated { get; }
IIdentity CurrentIdentity { get; }
IPrincipal CurrentUser { get; set; }
}
Avec une implémentation concrète comme :
public class SecurityContext : ISecurityContext
{
private readonly HttpContext _context;
public SecurityContext()
{
_context = HttpContext.Current;
}
public bool IsAuthenticated
{
get { return _context.Request.IsAuthenticated; }
}
public IIdentity CurrentIdentity
{
get { return _context.User.Identity; }
}
public IPrincipal CurrentUser
{
get { return _context.User; }
set { _context.User = value; }
}
}
Avec MVC RC 1, le ControllerContext enveloppe le HttpContext et l'expose comme une propriété. Cela rend le mocking beaucoup plus facile. Pour simuler une variable de session avec Moq, procédez comme suit :
var controller = new HomeController();
var context = MockRepository.GenerateStub<ControllerContext>();
context.Expect(x => x.HttpContext.Session["MyKey"]).Return("MyValue");
controller.ControllerContext = context;
Voir Le message de Scott Gu pour plus de détails.
J'ai trouvé que la moquerie était assez facile. Voici un exemple d'adaptation de la base httpContext (qui contient les objets requête, session et réponse) à l'aide de moq.
[TestMethod]
public void HowTo_CheckSession_With_TennisApp() {
var request = new Mock<HttpRequestBase>();
request.Expect(r => r.HttpMethod).Returns("GET");
var httpContext = new Mock<HttpContextBase>();
var session = new Mock<HttpSessionStateBase>();
httpContext.Expect(c => c.Request).Returns(request.Object);
httpContext.Expect(c => c.Session).Returns(session.Object);
session.Expect(c => c.Add("test", "something here"));
var playerController = new NewPlayerSignupController();
memberController.ControllerContext = new ControllerContext(new RequestContext(httpContext.Object, new RouteData()), playerController);
session.VerifyAll(); // function is trying to add the desired item to the session in the constructor
//TODO: Add Assertions
}
J'espère que cela vous aidera.
Scott Hanselman a publié un article sur comment créer un téléchargement de fichiers quickapp avec MVC et discute de la moquerie et aborde spécifiquement "Comment moquer les choses qui ne sont pas mock friendly".