所以我知道,当涉及到用户故事场景时,具体化是一件好事。然而,我经常会问自己:我的场景应该有多具体?
例如,对于用户故事:
为了让项目成员在项目上进行协作,作为项目经理,我希望能够注册新项目
我们可以有以下场景:
给定一个项目从未在系统中注册过,当项目经理注册该项目时,注册的项目应该出现在指定成员的项目列表中
或者我们可以更具体一些,比如:
鉴于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));
}
}