2010-03-23 7 views
28

J'essaye d'écrire un test unitaire pour mon contrôleur pour vérifier si une vue a été retournée correctement, mais ce contrôleur a un basecontroller qui accède au HttpContext.Current.Session. Chaque fois que je crée une nouvelle instance de mon contrôleur, il appelle le constructeur du basecontroller et le test échoue avec une exception de pointeur nul sur le HttpContext.Current.Session. Voici le code:Contrôleur de test unité ASP.NET MVC avec HttpContext

public class BaseController : Controller 
{  
    protected BaseController() 
    { 
     ViewData["UserID"] = HttpContext.Current.Session["UserID"]; 
    } 
} 

public class IndexController : BaseController 
{ 
    public ActionResult Index() 
    { 
     return View("Index.aspx"); 
    } 
} 

    [TestMethod] 
    public void Retrieve_IndexTest() 
    { 
     // Arrange 
     const string expectedViewName = "Index"; 

     IndexController controller = new IndexController(); 

     // Act 
     var result = controller.Index() as ViewResult; 

     // Assert 
     Assert.IsNotNull(result, "Should have returned a ViewResult"); 
     Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName); 
    } 

Toutes les idées sur la façon de se moquer (en utilisant QMC) la session qui est accessible dans le contrôleur de base de sorte que le test dans le contrôleur descendant fonctionnera?

Répondre

5

Si vous utilisez Typemock, vous pouvez le faire:

Isolate.WhenCalled(()=>controller.HttpContext.Current.Session["UserID"]) 
.WillReturn("your id"); 

Le code de test ressemblera:

[TestMethod] 
public void Retrieve_IndexTest() 
{ 
    // Arrange 
    const string expectedViewName = "Index"; 

    IndexController controller = new IndexController(); 
    Isolate.WhenCalled(()=>controller.HttpContext.Current.Session["UserID"]) 
    .WillReturn("your id"); 
    // Act 
    var result = controller.Index() as ViewResult; 

    // Assert 
    Assert.IsNotNull(result, "Should have returned a ViewResult"); 
    Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName); 
} 
3

Vous devriez probablement utiliser un ActionFilter au lieu d'une classe de base pour ce genre de chose

[UserIdBind] 
public class IndexController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View("Index.aspx"); 
    } 
} 
+0

Si j'utilise l'approche du filtre d'action que faudrait alors décorer chaque action avec cet attribut et avec environ 400 actions ISN 't possible – amurra

+0

@ user299592: Non, vous ne le feriez pas. Vous pouvez l'appliquer au niveau de la classe (comme dans l'exemple) et l'appliquer à chaque action de cette classe. Si vous pensez que cela va être plus d'efforts que de se moquer d'un contexte pour chaque test sur chaque action (peu ou pas de qui utilisent réellement le champ que vous définissez dans le constructeur), assez juste. – pdr

+0

Votre correct Je ne l'ai pas vu au niveau de la classe, mais le filtre d'action ne serait-il pas encore appelé lors de l'instanciation de l'objet contrôleur? – amurra

61

Sauf si vous utilisez Typemock ou Moles, you can't.

Dans ASP.NET MVC, vous n'êtes pas censé utiliser HttpContext.Current. Changez votre classe de base pour utiliser ControllerBase.ControllerContext - il a une propriété HttpContext qui expose la classe testable HttpContextBase.

Voici un exemple de la façon dont vous pouvez utiliser Moq pour mettre en place un HttpContextBase Mock:

var httpCtxStub = new Mock<HttpContextBase>(); 

var controllerCtx = new ControllerContext(); 
controllerCtx.HttpContext = httpCtxStub.Object; 

sut.ControllerContext = controllerCtx; 

// Exercise and verify the sut 

sut représente le système sous test (SUT), à savoir le contrôleur que vous souhaitez tester.

+0

pouvez-vous me diriger dans la direction de comment se moquer de cela avec Moles s'il vous plaît? – BritishDeveloper

+0

Certainement le chemin à parcourir; Microsoft a ajouté HttpContextBase pour cette raison précise. Maintenant, si seulement Cache et FormsAuthentication n'étaient pas scellés/statiques ... –

3

Snippet:

var request = new SimpleWorkerRequest("/dummy", @"c:\inetpub\wwwroot\dummy", "dummy.html", null, new StringWriter()); 
var context = new HttpContext(request); 
SessionStateUtility.AddHttpSessionStateToContext(context, new TestSession()); 
HttpContext.Current = context; 

mise en œuvre de TestSession():

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Web.SessionState; 

namespace m1k4.Framework.Test 
{ 
    public class TestSession : IHttpSessionState 
    { 
     private Dictionary<string, object> state = new Dictionary<string, object>(); 

     #region IHttpSessionState Members 

     public void Abandon() 
     { 
      throw new NotImplementedException(); 
     } 

     public void Add(string name, object value) 
     { 
      this.state.Add(name, value); 
     } 

     public void Clear() 
     { 
      throw new NotImplementedException(); 
     } 

     public int CodePage 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public System.Web.HttpCookieMode CookieMode 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public void CopyTo(Array array, int index) 
     { 
      throw new NotImplementedException(); 
     } 

     public int Count 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public System.Collections.IEnumerator GetEnumerator() 
     { 
      throw new NotImplementedException(); 
     } 

     public bool IsCookieless 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public bool IsNewSession 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public bool IsReadOnly 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public bool IsSynchronized 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public System.Collections.Specialized.NameObjectCollectionBase.KeysCollection Keys 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public int LCID 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public SessionStateMode Mode 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public void Remove(string name) 
     { 
      this.state.Remove(name); 
     } 

     public void RemoveAll() 
     { 
      this.state = new Dictionary<string, object>(); 
     } 

     public void RemoveAt(int index) 
     { 
      throw new NotImplementedException(); 
     } 

     public string SessionID 
     { 
      get 
      { 
       return "Test Session"; 
      } 
     } 

     public System.Web.HttpStaticObjectsCollection StaticObjects 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public object SyncRoot 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public int Timeout 
     { 
      get 
      { 
       return 10; 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public object this[int index] 
     { 
      get 
      { 
       throw new NotImplementedException(); 
      } 
      set 
      { 
       throw new NotImplementedException(); 
      } 
     } 

     public object this[string name] 
     { 
      get 
      { 
       return this.state[name]; 
      } 
      set 
      { 
       this.state[name] = value; 
      } 
     } 

     #endregion 
    } 
} 
+1

Si vous utilisez Rhino.Mocks, vous pouvez simplement faire 'SessionStateUtility.AddHttpSessionStateToContext (httpContext, MockRepository.GenerateStub ());' au lieu d'implémenter TestSession par vous-même. –

Questions connexes