Est-ce que j’écris correctement mes premières spécifications MSpec?

J’écris mes premières spécifications MSpec et je voulais des conseils. J’ai laissé les spécifications dans l’état “en attente”, mais le contexte est rempli. Y a-t-il des améliorations à apporter?

Pour référence, voici l’histoire et le premier scénario:

Story: "Blog admin logs in to the system" As a blog writer I want to be able to log in to my blog So that I can write posts and administer my blog Scenario: "Logs in from the login page" Given the user enters in correct credentials for a user in the system When the user clicks the "Login" button Then log the user in and redirect to the admin panel with a message stating that he logged in correctly 

Et le code MSpec (certaines parties sont découpées), notez que je devais alias le délégué MSpec It raison d’un conflit avec Moq.It :

 using MoqIt = Moq.It; using ThenIt = Machine.Specifications.It; [Subject("User sortinges logging in")] public class When_user_enters_valid_credentials : With_user_existing_in_membership { protected static ActionResult result; Because of = () => { result = loginController.Login(validUsername, validPassword); }; ThenIt should_log_the_user_in; ThenIt should_redirect_the_user_to_the_admin_panel; ThenIt should_show_message_confirming_successful_login; } public abstract class With_user_existing_in_membership { protected static Mock membershipMock; protected static ssortingng validUsername; protected static ssortingng validPassword; protected static LoginController loginController; Establish context =()=> { membershipMock = new Mock(); validUsername = "ValidUsername"; validPassword = "ValidPassword"; //make sure it's treated as valid usernames and password membershipMock .Setup(m => m.Validate( MoqIt.Is(s => s == validUsername), MoqIt.Is(s => s == validPassword))) .Returns(true); loginController = new LoginController(membershipMock.Object); }; } 

Le contexte est bon. J’aime la façon dont vous avez résolu le conflit avec les alias. Je dirais que l’alias Moq peut être amélioré. Considérez quelque chose comme une phrase. Par exemple, Param.Is ou Value.Is .

Quelques notes, avec des extraits de code, puis toute la spécification réécrite en bas.

Le scénario est votre Subject

Le sujet peut être le scénario de l’histoire. De plus, il est rendu avec votre rapport de test (particulièrement intéressant dans le rapport HTML).

 [Subject("Login Page")] 

Ne perdez pas de temps avec “Avec” les classes de base nommées

Le créateur de MSpec, Aaron Jensen, n’a plus utilisé la syntaxe «With». Les noms de classe de contexte n’apparaissent pour aucun rapport, évitez donc de passer du temps à inventer un nom significatif.

 public abstract class MembershipContext 

Le nom donné est votre nom de classe de spécifications

Nommez la classe de spécifications concrète après le donné dans votre histoire. Surtout que le nom de la classe de base n’est signalé nulle part, vous risquez de perdre la moitié de votre contexte dans le rapport! Vous devriez également éviter de mettre le nom du système sous test dans les noms de classe de contexte. Cela rend vos contextes plus conviviaux pour la refactorisation du système testé.

 public class When_an_existing_user_enters_valid_credentials 

Les classes de spécifications de base ne doivent contenir que l’initialisation générale

Et sont souvent inutiles. Ils conduisent à la séparation des phases Arrangement et Act. Utilisez une classe de base pour l’initialisation des champs communs, comme la configuration de dépendances simulées. Mais, vous ne devriez pas vous moquer du comportement dans une classe de base. Et vous ne devriez pas mettre d’informations spécifiques au contexte dans la classe de base. Dans votre exemple, le nom d’utilisateur / mot de passe. De cette façon, vous pouvez créer un second contexte avec des informations d’identification non valides.

 Establish context = () => { membership = new Mock(); loginController = new LoginController(membership.Object); }; 

Les champs de la classe de spécification concrète doivent être privés

Cela réduit la “cérémonie” de la langue dans votre test. Vous devez les placer en dessous de tous les delegates spécifiques à MSpec, car ces parties de la spécification racontent l’essentiel de l’histoire.

 static ActionResult result; 

La révision des spécifications

La spécification est un excellent exemple d’établissement d’un contexte global MembershipContext et l’inheritance dans un contexte spécifique à la spécification (donc, l’ Establish supplémentaire).

 [Subject("Login Page")] public class When_an_existing_user_enters_valid_credentials : MembershipContext { Establish context = () => { membership .Setup(m => m.Validate( Param.Is(s => s == username), Param.Is(s => s == password))) .Returns(true); }; Because of = () => result = loginController.Login(username, password); It should_log_the_user_in; It should_redirect_the_user_to_the_admin_panel; It should_show_message_confirming_successful_login; static ActionResult result; const ssortingng username = "username"; const ssortingng password = "password"; } public abstract class MembershipContext { Establish context = () => { membership = new Mock(); loginController = new LoginController(membership.Object); }; protected static Mock membership; protected static LoginController loginController; }