是否有特定的用户故事场景邪恶?

时间:2011-04-03 03:37:05

标签: c# bdd user-stories storyq

所以我知道,在用户故事情景方面,being specificgood thing。但是,我经常谈到自己的问题:我的情景有多具体?

例如,对于用户故事:

  

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

我们可以有以下情况:

  

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

或者我们可以更具体地说:

  

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

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

  • 更符合现实世界(我们没有作为项目经理工作的存根......或者我们呢?)
  • 在规范上下文中需要时更容易引用(否则,我将继续说“那个项目经理”或“注册项目的项目经理”等等。

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

非常感谢!

<小时/> 的更新

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

我将尝试通过使用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));
    }
}

5 个答案:

答案 0 :(得分:3)

您提供的第一个“方案”实际上是验收标准。它指定了一个适用于所有类型的项目经理,成员和指定项目的规则。

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

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

您可能已经看到在讨论场景时使用特定数据的难易程度。还要记住:

  • 进行对话
  • 更重要
  • 捕获对话,这比
  • 更重要
  • 自动化对话

如果你同时做这三件事,那就值得称赞,但为了自动化,不要在谈话中妥协。

答案 1 :(得分:2)

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

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

我可以给出的最重要的建议是,在定义你的人物角色时,重要的是要非常具体地说明是什么令人愉悦/激励/挫败他们,但这种特殊性应该是整个世界或计算中的。一般 - 不要将这些东西与产品的特定方面或产品的个人愿望联系起来,否则1)人格将很快变得过时并需要重新创建2)这些人最终将被用作主观武器进一步提升您的个人愿望,而不是作为一种基于事实的工具,以改善为真实的人提供最好的产品。说起来容易做起来难得多。

答案 2 :(得分:1)

good 为那里的角色使用名称,因为它们使故事更容易理解;他们更喜欢你的灵长类大脑,因为它喜欢个人,讨厌抽象。但是,你必须小心!尽量确保你使用的名字与你实际工作的任何人的名字都不匹配 - 这是非常令人困惑的 - 并且不会对偏见进行编码 - 项目不是偏见的事情,因为它不能有意见。也不要对不同的角色使用相同的名称;虽然现实可能是一个混乱的组合,人们有很多角色,但用户故事不应该混淆,因为它只是简单的混淆。

答案 3 :(得分:1)

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

  

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

VS

  

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

请注意,上面第二个示例的措辞与您在问题中提供的第一个示例没有太大区别,但它略有不同,因此它看起来好像它更完整一些。我认为这是你可能觉得缺少的一种方式,如果是这种情况,我会把它视为一种“故事气味”,如果是这样的话,我会不断提问和重写直到故事情节感觉更完整。

就我个人而言,我发现角色的使用让我分心于手头的任务,而且我不喜欢最终看到我的测试代码,这些代码散落着看起来不像我正在测试的内容的文本。另一方面,如果您采用数据驱动的方法并且为此目的定义某种数据结构,那么在该结构中填充名称在其测试范围内可能有意义是有意义的。

我认为使用角色的风险之一是它们有时最终可以替代懒惰的方法命名,甚至更糟糕的是作为无聊程序员尝试在代码中注入一点点幽默的手段。并不是说我觉得用你的名字带来一点乐趣是不好的,但是如果他们没有为利益相关者提供价值,那么就不应该使用它们。

然而,另一个想法发生在我身上,你可以充分利用两个世界。如果您将用户角色指定为要提供给故事场景的数据,那么您可以保持代码清洁,但是您可以使输出在实际测试执行方面看起来更具体一些。例如:

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();

答案 4 :(得分:0)

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

斯科特也可能参与市场营销,而* Magret_the_project_manager *可能与Scott有不同的责任