我是否正确编写了我的第一个MSpec规范?

时间:2009-07-26 11:12:23

标签: c# bdd mspec

我正在编写我的第一个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的冲突,我必须为MSpec 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);
    };
}

1 个答案:

答案 0 :(得分:55)

上下文看起来不错。我喜欢你用别名解决冲突的It的方式。我认为可以改进Moq别名。考虑类似句子的东西。例如,Param.Is<T>Value.Is<T>

一些注释,使用代码片段,然后在底部重写整个规范。

情景是您的Subject

主题可以是故事中的场景。另外,它会使用您的测试运行报告进行渲染(在HTML报告中特别好)。

[Subject("Login Page")]

不要在“With”命名基类上浪费时间

MSpec的创建者Aaron Jensen,has reverted完全使用“With”语法。上下文类名称不会显示在任何报告中,因此请避免花时间创建有意义的名称。

public abstract class MembershipContext

Given是你的spec类名

在故事中的Given之后命名具体的spec类。特别是因为基类名称没有在任何地方报告,您可能会在报告中丢失一半的上下文!您还应该避免在上下文类名称中输入正在测试的系统的名称。这使您的上下文更友好地重构被测系统。

public class When_an_existing_user_enters_valid_credentials

基本规范类应仅包含常规初始化

通常没必要。它们导致安排和行动阶段的分离。使用基类进行公共字段初始化,例如设置模拟依赖项。但是,您不应该在基类中模拟行为。并且您不应将特定于上下文的信息放在基类中。在您的示例中,用户名/密码。这样,您可以创建具有无效凭据的第二个上下文。

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;
}