Frage

Ich schreibe meine erste MSpec Spezifikationen und ich einige Hinweise wollte. Ich verließ die Spezifikationen in dem „pending“ Zustand, aber der Zusammenhang ist ausgefüllt. Gibt es irgendwelche Verbesserungen gemacht werden?

Als Referenz ist dies die Geschichte und die erste Szenario:

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

Und der MSpec Code (einige Teile snipped), bemerkt, dass ich alias hatte die MSpec It Delegierten aufgrund eines Konflikts mit 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);
    };
}
War es hilfreich?

Lösung

Der Kontext sieht gut aus. Ich mag die Art und Weise Sie den Konflikt It mit Aliase gelöst. Ich würde argumentieren, dass der Moq alias verbessert werden kann. Betrachten wir etwas Satz-like. Zum Beispiel Param.Is<T> oder Value.Is<T>.

Einige Anmerkungen, mit Code-Schnipsel, dann ist die ganze spec am Boden neu geschrieben.

Das Szenario ist Ihr Subject

kann das Subjekt das Szenario aus der Geschichte sein. Außerdem ist es mit Ihrem Testlauf Bericht (besonders schön in dem HTML-Bericht) gerendert wird.

[Subject("Login Page")]

Verschwenden Sie keine Zeit auf „Mit“ genannt Basisklassen

MSpec Schöpfer, Aaron Jensen, wird von der Verwendung der "Mit" Syntax völlig rückgängig gemacht . Kontextklassennamen zeigen nicht für alle Berichte, also vermeiden die Ausgaben Zeit, um einen aussagekräftigen Namen zu erfinden.

public abstract class MembershipContext

Die Gegeben ist die Spec-Klassennamen

Name der Beton spec Klasse nach dem in der Geschichte gegeben. Vor allem, da der Name der Basisklasse ist nicht überall berichtet, könnten Sie die Hälfte Ihres Kontext in dem Bericht zu verlieren sein! Sie sollten auch vermeiden, den Namen des zu testenden Systems in Zusammenhang Klassennamen setzen. Das macht Ihre Kontexte freundlicher, um das System im Test Refactoring.

public class When_an_existing_user_enters_valid_credentials

Basis spec Klassen sollten nur allgemeine Initialisierung enthalten

Und sind oft unnötig. Sie führen zu einer Trennung der Vereinbaren und Act Phasen. Verwenden Sie eine Basisklasse für gemeinsame Feldinitialisierung, wie verspottet Abhängigkeiten einrichten. Aber man sollte nicht das Verhalten in einer Basisklasse verspotten. Und Sie sollten nicht kontextspezifische Informationen in der Basisklasse setzen. In Ihrem Beispiel der Benutzername / Passwort. Auf diese Weise können Sie einen zweiten Kontext mit ungültigen Anmeldeinformationen erstellen.

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

Felder in der konkreten spec Klasse sollte privat

sein

Es reduziert die „Zeremonie“ der Sprache in Ihrem Test. Sie sollten sie unter all den MSpec bestimmten Delegierten stellen, da diese Teile der Spezifikation der größte Teil der Geschichte erzählen.

static ActionResult result;

Die Spec Overhaul

Die Spezifikation hier ist ein hervorragendes Beispiel für einen globalen Kontext MembershipContext Festlegung und es in einem Kontext, der spezifisch auf die Spezifikation (also die zusätzliche Establish) erbt.

[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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top