6

所以我知道,当涉及到用户故事场景时,具体化一件好事。然而,我经常会问自己:我的场景应该有多具体?

例如,对于用户故事:

为了让项目成员在项目上进行协作,作为项目经理,我希望能够注册新项目

我们可以有以下场景:

给定一个项目从未在系统中注册过,当项目经理注册该项目时,注册的项目应该出现在指定成员的项目列表中

或者我们可以更具体一些,比如:

鉴于Scott是项目经理,并且stackoverflow 集成项目从未在系统中注册,当Scott注册stackoverflow 集成项目时指定Jane为项目成员,则stackoverflow 集成项目应该出现在Jane的项目列表中

在编写 BDD 规范时,我发现第二个“更具体”的规范非常方便。有类似 scottTheProjectManager 而不是 projectManagerStub 的地方是:

  • 更符合现实世界(我们没有作为项目经理工作的存根……还是我们?)
  • 在该规范上下文中需要时更容易参考(否则,我会一直说“那个项目经理”或“注册项目的项目经理”......等等。

我的结论正确吗?当故事发生变化时,这种特殊性会伤害我吗?

非常感谢!


更新

上面的问题不仅是关于使用人名而不是角色名,而是关于用真实实例的名称替换场景中的所有占位符。通过真实的例子,我并不是说我们实际上有一个叫 Scott 的人担任项目经理,它只是给抽象占位符命名以实现上述好处。

我将尝试通过包含以下代码来展示这些好处是如何实现的,这些代码表示使用 StoryQ 框架的完整 BDD 样式规范

[TestFixture]
public class ProjectRegistrationSpecs
{
    [Test]
    public void ProjectRegistration()
    {
        new Story("Project Registration")
            .InOrderTo("allow project members to collaborate over a project")
            .AsA("project manager")
            .IWant("to be able to register new projects")
                .WithScenario("New Project Registration")
                    .Given(ScottIsAProjectManager)
                        .And(StackoverflowIntegrationProjectHasNeverBeenRegistered)
                    .When(ScottRegistersStackoverflowIntegrationProjectSpecifyingJaneAsAnAnalyst)
                    .Then(StackoverflowIntegrationProjectShouldAppearInJanesListOfProjects)
        .Execute();
}

//Since Scott and Jane are just instances that have meaning in the context of this user story only, they're defined private
private ProjectManager scottTheProjectManager;
private Project stackOverFlowIntegrationProject;
private Employee janeTheAnalyst; 

    //Initialize the stubs in the constructor
    public ProjectRegistrationSpecs()
    {
        scottTheProjectManager = new ProjectManager()
        {
            Id = new Guid("{A1596CFC-5FA5-4f67-AC7E-5B140F312D52}")
        };

        stackOverFlowIntegrationProject = new Project()
        {
            Id = new Guid("{F4CD5DDE-861E-4e18-8021-730B7F47C232}"),
            Name = "Stack Overflow Integration"
        };
    }
    private void ScottIsAProjectManager()
    {
        container.Get<IDataProvider>().Repository<ProjectManager>().Add(scottTheProjectManager);
    }
    private void StackoverflowIntegrationProjectHasNeverBeenRegisteredInTheSystem()
    {
        var provider = container.Get<IDataProvider>();
        var project = provider.Repository<Project>().SingleOrDefault(p => p.Name == stackOverFlowIntegrationProject.Name);
        if (null != project)
        provider.Repository<Project>().Delete(project);
    }
    private void ScottRegistersStackoverflowIntegrationProjectSpecifyingJaneAsAProjectMember()
    {
        stackOverFlowIntegrationProject.Members.Add(janeTheAnalyst);
        scottTheProjectManager.RegisterProject(stackOverFlowIntegrationProject);
    }

    //instead of saying something like TheProjectThatWasAddedByTheProjectManagerShouldAppearInTheProjectMembersList, we have: 
    private void StackoverflowIntegrationProjectShouldAppearInJanesListOfProjects()
    {
        Assert.That(janeTheAnalyst.Projects.Any(p => p.Id == stackOverFlowIntegrationProject.Id));
    }
}
4

5 回答 5

3

您给出的第一个“场景”实际上是验收标准。它指定了适用于所有类型的项目经理、成员和指定项目的规则。

第二种情况是使用实际数据的验收标准示例。BDD 最重要的方面是在对话中使用这样的示例,以便可以讨论故事接受标准的任何其他方面。

例如,假设stackoverflow 集成项目已经注册,当 Scott 再次尝试注册它时会发生什么?是否有任何情况可以拒绝简对项目的分配?简对项目的分配是唯一有价值的结果吗?她会收到一封电子邮件吗?

您可能已经看到在讨论场景时使用特定数据是多么容易。还要记住:

  • 进行对话
  • 捕捉比这更重要的对话
  • 使对话自动化

如果你能同时做这三件事,那就太赞了,但不要为了自动化而在对话上妥协。

于 2011-04-07T14:19:51.940 回答
2

“用户角色”是一个非常强大但难以掌握的概念。如果做得好,他们可以引导您实现简化、优化的用户体验。做错了,他们会占用时间并给团队中的人一个主观的理由互相大喊大叫。

查看http://www.agile-ux.com/2009/12/02/personas-in-agile-development-yes-we-can/作为起点。有大量关于这个主题的文献,但大多不是特定于 BDD。

我可以给出的最重要的建议是,在定义你的角色时,重要的是要非常具体地说明什么让他们高兴/激励/挫败,但具体应该针对整个世界或一般计算 - 不要不要将这些东西与产品的特定方面或产品的个人愿望联系起来,否则 1) 角色很快就会过时并需要重新创建;2) 角色最终会被用作促进个人发展的主观武器抱负,而不是作为一种基于事实的改进工具,为真实的人提供最好的产品。这说起来容易做起来难。

于 2011-04-03T04:21:56.927 回答
1

比较您的示例中的以下内容:

鉴于 Scott 是项目经理,并且 stackoverflow 集成项目从未在系统中注册,当 Scott 注册 stackoverflow 集成项目时指定 Jane 为项目成员,则 stackoverflow 集成项目应该出现在 Jane 的项目列表中

对比:

给定一个项目经理和一个未注册的项目,当项目经理注册项目并指定一个团队成员时,项目应该出现在团队成员的项目列表中。

请注意,上面第二个示例的措辞与您在问题中给出的第一个示例并没有太大的不同,但它有细微的不同,因此读起来好像更完整一些。我认为在某种程度上你可能会觉得这是缺失的,如果是这样的话,我会把它当作一种“故事的味道”,如果是这样的话,我会继续提问并改写直到故事/场景感觉更完整。

就我个人而言,我发现角色的使用分散了我手头任务的注意力,而且我不喜欢我的测试代码中满是乱七八糟的文本,这些文本读起来好像不属于我正在测试的东西。另一方面,如果您采用数据驱动的方法并为此目的定义了某种数据结构,那么使用在测试范围内有意义的名称填充该结构是有意义的。

我认为使用角色的风险之一是它们有时最终会成为惰性方法命名的替代品,或者更糟糕的是,作为无聊的程序员尝试在他们的代码中注入一点幽默的一种手段。并不是说我认为用你的名字找点乐子是不好的,但如果它们不能为利益相关者提供价值,那么就不应该使用它们。

不过,我想到了另一个想法,即您可以两全其美。如果您将您的用户角色指定为数据以提供给您的故事场景,那么您将受益于保持代码简洁明了,但您可以使输出在实际测试执行方面显得更加具体。例如:

new Story("Project Registration")
        .InOrderTo("allow project members to collaborate over a project")
        .AsA("project manager")
        .IWant("to be able to register new projects")
            .WithScenario("New Project Registration")
                .Given(AProjectManager, "Scott")
                    .And(AnUnRegisteredProject, "Stack Overflow Integration")
                .When(TheProjectManagerRegistersTheProject)
                    .And(TheProjectManagerSpecifiesATeamMember, "Jane")
                .Then(ThenTheProjectShouldAppearInTheTeamMembersListOfProjects)
    .Execute();
于 2011-10-08T09:30:53.050 回答
1

最好为那里角色命名,因为它们更容易理解故事;它们更多地参与了灵长类动物的大脑,因为它喜欢个人并且讨厌抽象。但是,您必须小心!尽量确保你使用的名字与你实际合作的人的名字不匹配——那会非常混乱——并且不要编码偏见——这个项目不是一个有偏见的东西,因为它不能有意见。也不要为不同的角色使用相同的名称;虽然现实可能是人们扮演许多角色的混乱组合,但用户故事不应该以这种方式混淆,因为它只是令人困惑。

于 2011-04-03T07:15:23.700 回答
0

虽然您的方法具有指定的特定用户间隔对于领域专家来说更容易理解(因为领域专家知道 *Scott_the_project_manager* 和他的任务),但我认为这种方法违反了Single_responsibility_principle:一个人可以有多个角色。

Scott 也可能参与营销,*Magret_the_project_manager* 可能与 Scott 有不同的职责

于 2011-04-03T06:40:38.887 回答