Variable de session moqueuse dans le test unitaire avec Moles

Méthode Je suis des tests unitaires vérifie une variable de session comme

if(Session["somevar"] != null) { // rest of the code } 

Dans mon test, impossible de se débarrasser de cela puisque Session est nul, il renvoie une exception de référence nulle.

Pour éviter cela, j’ai essayé de me moquer comme ci-dessous mais pas de chance

 System.Web.Moles.MHttpContext.AllInstances.SessionGet = (HttpContext cntx) => { return (HttpSessionState)cntx.Session["somevar"]; } 

J’ai même essayé de mentionner la méthode ici pour simuler HttpContext puis faire ci-dessous

 HttpContext.Current = new HttpContext(workerRequest); HttpContext.Current.Session["somevar"] = value; 

Mais encore une fois pas de chance. Cette fois, bien que HttpContext.Current ne soit pas null, mais HttpContext.Current.Session et lève donc une exception null ref.

Toute idée de comment puis-je me moquer de cela / par passer ceci dans mon test [Sans utiliser de DLL externe ni de changement de code principal. Désolé, mais je n’ai pas les moyens de le faire].

Merci et appréciez beaucoup votre aide.

Mise à jour 2013:

La mauvaise nouvelle maintenant est que la structure Moles était un projet Microsoft Research (MSR) et ne sera pas prise en charge dans Visual Studio 2012 . La bonne nouvelle est que Microsoft a maintenant intégré le projet MSR dans le framework principal en tant que Microsoft Fakes .

J’ai trouvé un article qui résout votre problème en utilisant le framework Fakes au lieu du framework Moles:

http://blog.christopheargento.net/2013/02/02/testing-untestable-code-thanks-to-ms-fakes/

Voici une version mise à jour de ma réponse précédente qui utilise le framework Fakes au lieu de Moles.

 using System.Web.Fakes; // ... var sessionState = new Dictionary(); ShimHttpContext.CurrentGet = () => new ShimHttpContext(); ShimHttpContext.AllInstances.SessionGet = (o) => new ShimHttpSessionState { ItemGetSsortingng = (key) => { object result = null; sessionState.TryGetValue(key, out result); return result; } }; 

Vous pourrez peut-être même faire en sorte que cela ressemble davantage à la version de Moles que j’ai déjà publiée, bien que je ne l’aie pas encore essayée. Je suis en train d’adapter le code de l’article à ma réponse 🙂


Avant 2013, éditez:

Vous avez dit que vous vouliez éviter de changer le code sous test. Bien que je pense que cela devrait être changé, comme accéder directement à un état de session comme cela est une mauvaise idée, je peux comprendre d’où vous venez (j’ai déjà fait l’object d’un test …).

J’ai trouvé ce fil décrivant comment quelqu’un a HttpContext fois HttpContext et HttpSessionState pour contourner ce problème .

Leur code a fini par ressembler à ceci:

 MHttpContext.CurrentGet = () => new MHttpContext { SessionGet = () => new MHttpSessionState { ItemGetSsortingng = (key) => { if (key == "some") return "someSsortingng"/* or any other object*/; else return null; } } }; 

J’irais encore plus loin et implémenter ItemGetSsortingng avec un dictionnaire:

 var sessionState = new Dictionary(); MHttpContext.CurrentGet = // ... { // ... ItemGetSsortingng = (key) => { object result = null; sessionState.TryGetValue(key, out result); return result; } 

Avant édition:

Je résous généralement des problèmes comme celui-ci en encapsulant un état global avec une classe abstraite ou une interface pouvant être instanciée et simulée. Ensuite, au lieu d’accéder directement à l’état global, j’injecte une instance de ma classe abstraite ou interface dans le code qui l’utilise.

Cela me permet de simuler le comportement global et de faire en sorte que mes tests ne dépendent pas ou n’exercent pas ce comportement sans rapport.

Voici une façon de faire (je jouerais un peu avec le factoring):

 public interface ISessionContext { object this[ssortingng propertyName] { get; set; } } public class ServerContext : ISessionContext { public object this[ssortingng propertyName] { get { return HttpContext.Current.Session[propertyName]; } set { HttpContext.Current.Session[propertyName] = value; } } } public class SomeClassThatUsesSessionState { private readonly ISessionContext sessionContext; public SomeClassThatUsesSessionState(ISessionContext sessionContext) { this.sessionContext = sessionContext; } public void SomeMethodThatUsesSessionState() { ssortingng somevar = (ssortingng)sessionContext["somevar"]; // todo: do something with somevar } } 

Cela nécessiterait des modifications de votre code sous test, mais c’est le type de modification qui convient à la fois pour la testabilité et la portabilité du code.