40 votes

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 ont été coupées), notez que je devais aliaser le délégué MSpec It raison d’un conflit avec Moq.It :

 using MoqIt = Moq.It;
using ThenIt = Machine.Specifications.It;

[Subject("User tries 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<ISiteMembership> membershipMock;
    protected static string validUsername;
    protected static string validPassword;
    protected static LoginController loginController;

    Establish context =()=>
    {
        membershipMock = new Mock<ISiteMembership>();
        validUsername = "ValidUsername";
        validPassword = "ValidPassword";
        //make sure it's treated as valid usernames and password
        membershipMock
            .Setup<bool>(m => m.Validate(
                MoqIt.Is<string>(s => s == validUsername), 
                MoqIt.Is<string>(s => s == validPassword)))
            .Returns(true);
        loginController = new LoginController(membershipMock.Object);
    };
}
 

55voto

Alexander Groß Points 4217

Le contexte semble bon. J'aime la façon dont vous avez résolu le conflit It avec des alias. Je dirais que le Moq alias peut être améliorée. Envisager quelque chose de phrase-comme. Par exemple, Param.Is<T> ou Value.Is<T>.

Quelques notes, avec des extraits de code, puis l'ensemble de la spec ré-bas.

Le Scénario est votre Subject

Le Sujet peut être le Scénario de l'histoire. De Plus, il s'est rendu avec votre test de rapport (surtout dans le rapport HTML).

[Subject("Login Page")]

Ne perdez pas de temps sur "Avec" le nom de la base de classes

MSpec du créateur, Aaron Jensen, a été rétablie à partir de l'aide de la "Avec la" syntaxe tout à fait. Contexte de la classe des noms ne s'affichent pas pour les rapports, afin d'éviter de passer du temps à inventer un nom significatif.

public abstract class MembershipContext

La Donnée est votre spec nom de la classe

Nom du béton spec après la dans votre histoire. Surtout depuis que le nom de classe de base n'est pas n'importe où, vous pourriez perdre la moitié de votre contexte dans le rapport! Vous devriez aussi éviter de mettre le nom du système sous test dans le contexte de la classe des noms. Cela rend votre contextes plus respectueuses de refactoring du système sous test.

public class When_an_existing_user_enters_valid_credentials

Base spec classes doit contenir uniquement généraux de l'initialisation

Et sont souvent inutiles. Ils mènent à la séparation de l'Organiser et de la Loi sur les phases. L'utilisation d'une classe de base pour la commune de champ d'initialisation, comme la mise en place moqué de dépendances. Mais, vous ne devriez pas vous moquer de comportement dans une classe de base. Et vous ne devriez pas mettre sur le contexte spécifique de l'information dans la classe de base. Dans votre exemple, le nom d'utilisateur/mot de passe. De cette façon, vous pouvez créer un deuxième contexte avec des informations d'identification non valides.

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

Les champs dans le béton spec devrait être privé

Il réduit la "cérémonie" de la langue dans votre test. Vous devriez les placer au-dessous de tous les MSpec spécifiques délégués, comme les parties de la spécification dire la plupart de l'histoire.

static ActionResult result;

La Spécification De La Révision

Les spec c'est un excellent exemple de la création d'un contexte global MembershipContext et d'en hériter dans un contexte spécifique à l'spec (ainsi, la plus - Establish).

[Subject("Login Page")]
public class When_an_existing_user_enters_valid_credentials : MembershipContext 
{
    Establish context = () =>
    {
        membership
            .Setup<bool>(m => m.Validate(
                Param.Is<string>(s => s == username), 
                Param.Is<string>(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 string username = "username";
    const string password = "password";
}

public abstract class MembershipContext 
{
    Establish context = () =>
    {
        membership = new Mock<ISiteMembership>();
        loginController = new LoginController(membershipMock.Object);
    };

    protected static Mock<ISiteMembership> membership;
    protected static LoginController loginController;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X