40

初めての MSpec 仕様を書いているので、ガイダンスが必要でした。スペックを「保留」状態のままにしましたが、コンテキストは記入済みです。改善すべき点はありますか?

参考までに、これはストーリーと最初のシナリオです。

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

そして、MSpec コード (いくつかの部分は切り取られていますIt) 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);
    };
}
4

1 に答える 1

55

文脈は良さそうです。Itエイリアスとの競合を解決した方法が気に入っています。Moqエイリアスは改善できると私は主張します。文のようなものを考えてみましょう。たとえば、Param.Is<T>またはValue.Is<T>.

いくつかのメモとコード スニペット、および最後に仕様全体を書き直しました。

シナリオはあなたのSubject

サブジェクトは、ストーリーのシナリオにすることができます。さらに、テスト実行レポートでレンダリングされます (特に、HTML レポートで優れています)。

[Subject("Login Page")]

"With" 名前付き基底クラスで時間を無駄にしないでください

MSpec の作成者である Aaron Jensen は "With" 構文の使用を完全にやめました。コンテキスト クラス名はどのレポートにも表示されないため、意味のある名前を考え出すのに時間を費やすことは避けてください。

public abstract class MembershipContext

ギブンはあなたの仕様クラス名です

ストーリーの中で、Given にちなんで具象仕様クラスに名前を付けます。特に、基本クラス名はどこにも報告されていないため、レポート内のコンテキストの半分が失われる可能性があります! また、テスト対象のシステムの名前をコンテキスト クラス名に含めないようにする必要があります。これにより、テスト中のシステムをリファクタリングしやすくなります。

public class When_an_existing_user_enters_valid_credentials

基本仕様クラスには、一般的な初期化のみを含める必要があります

そして、しばしば不必要です。それらは、アレンジフェーズとアクトフェーズの分離につながります。モック化された依存関係の設定など、一般的なフィールドの初期化には基本クラスを使用します。ただし、基本クラスで動作をモックしないでください。また、コンテキスト固有の情報を基本クラスに入れるべきではありません。あなたの例では、ユーザー名/パスワードです。このようにして、無効な認証情報を持つ 2 番目のコンテキストを作成できます。

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

具体的な仕様クラスのフィールドは非公開にする必要があります

テストでの言語の「儀式」を減らします。仕様のこれらの部分がほとんどのストーリーを伝えるため、MSpec 固有のすべてのデリゲートの下に配置する必要があります。

static ActionResult result;

スペックオーバーホール

ここでの仕様は、グローバル コンテキストを確立し、MembershipContextそれを仕様に固有のコンテキスト (したがって、追加の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(membership.Object);
    };

    protected static Mock<ISiteMembership> membership;
    protected static LoginController loginController;
}
于 2009-08-02T13:18:13.200 に答える