Pregunta

Estoy escribiendo mis primeras especificaciones MSpec y yo quería un poco de orientación. Salí de las especificaciones en el estado "pendiente", pero el contexto es llenada. ¿Hay que hacerse mejoras?

A modo de referencia, esta es la historia y el primer escenario:

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

Y el código MSpec (algunas partes cortan con tijeras), cuenta que tenía que ser alias el delegado It MSpec debido a un conflicto con 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);
    };
}
¿Fue útil?

Solución

El contexto se ve bien. Me gusta la forma en que resolvió el conflicto con It alias. Yo diría que el alias Moq se puede mejorar. Considerar algo frase similar. Por ejemplo, Param.Is<T> o Value.Is<T>.

Algunas notas, con fragmentos de código, a continuación, toda la especificación reescrito en la parte inferior.

El escenario es su Subject

El sujeto puede ser el escenario de la historia. Además, se representa con su informe de prueba de funcionamiento (especialmente agradable en el informe HTML).

[Subject("Login Page")]

No pierda el tiempo en "Con" clases base nombrados

El creador de MSpec, Aaron Jensen, ha revertido de utilizar el "con" sintaxis completo. nombres de las clases contexto no aparecen por ningún informe, por lo que evitar pasar tiempo inventando un nombre significativo.

public abstract class MembershipContext

El dado es el nombre de la clase de especificaciones

nombre de la clase de especificaciones concreto después de lo dado en su historia. Sobre todo porque el nombre de la clase base no se informó de ninguna parte, usted podría estar perdiendo la mitad de su contexto en el informe! También debe evitar poner el nombre del sistema que se está probando en los nombres de clases de contexto. Esto hace que sus contextos más amigable con la refactorización del sistema bajo prueba.

public class When_an_existing_user_enters_valid_credentials

clases de especificaciones de base debe contener únicamente la inicialización en general

Y son a menudo innecesario. Conducen a la separación de las fases de organizar y actuar. Utilice una clase base para la inicialización de campo común, como la creación de dependencias burlado. Sin embargo, no debe burlarse de comportamiento en una clase base. Y usted no debe poner la información específica del contexto de la clase base. En el ejemplo, el nombre de usuario / contraseña. De esta manera, se puede crear un segundo contexto con credenciales no son válidas.

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

Los campos en la clase de especificaciones concreto debe ser

privados

Se reduce la "ceremonia" de la lengua en su prueba. Usted debe colocarlos debajo de todos los delegados específicos MSpec, como aquellas partes de la especificación dicen la mayor parte de la historia.

static ActionResult result;

El Reacondicionamiento Spec

La especificación aquí es un ejemplo excelente de establecer un contexto global y MembershipContext heredarlo en un contexto específico a la especificación (por lo tanto, la Establish adicional).

[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(membership.Object);
    };

    protected static Mock<ISiteMembership> membership;
    protected static LoginController loginController;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top