我是否正确地编写了我的第一个 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 代码(某些部分被剪掉),请注意,由于与 Moq.It< 冲突,我必须为 MSpec
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);
};
}
I'm writing my first MSpec specifications and I wanted some guidance. I left the specs in the "pending" state, but the context is filled out. Are there any improvements to be made?
For reference, this is the story and first scenario:
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
And the MSpec code (some parts snipped), notice that I had to alias the MSpec It
delegate due to a conflict with 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);
};
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
上下文看起来不错。 我喜欢您用别名解决
It
冲突的方式。 我认为 Moq 别名可以改进。 考虑类似句子的东西。 例如,Param.Is
或Value.Is
。一些注释,带有代码片段,然后在底部重写整个规范。
场景是您的
主题
主题可以是故事中的场景。 另外,它会与您的测试运行报告一起呈现(在 HTML 报告中尤其好)。
不要在“With”命名基类上浪费时间
MSpec 的创建者 Aaron Jensen,已完全恢复使用“With”语法。 上下文类名称不会显示在任何报告中,因此请避免花时间发明一个有意义的名称。
Give 是您的规范类名称
在故事中的 Give 后面命名具体的规范类。 特别是由于基类名称没有在任何地方报告,您可能会丢失报告中一半的上下文! 您还应该避免将被测试系统的名称放在上下文类名称中。 这使得您的环境更适合重构被测系统。
基础规范类应该只包含一般初始化
并且通常是不必要的。 它们导致安排和行动阶段的分离。 使用基类进行公共字段初始化,例如设置模拟依赖项。 但是,您不应该模拟基类中的行为。 并且您不应该将特定于上下文的信息放入基类中。 在您的示例中,用户名/密码。 这样,您可以使用无效凭据创建第二个上下文。
具体规范类中的字段应该是私有的,
它减少了测试中语言的“仪式”。 您应该将它们放置在所有 MSpec 特定委托的下方,因为规范的这些部分讲述了大部分内容。
规范大修
此处的规范是建立全局上下文
MembershipContext
并在特定于规范的上下文中继承它的绝佳示例(因此,需要附加Establish
)。The context looks good. I like the way you solved the conflicting
It
with aliases. I would argue that the Moq alias can be improved. Consider something sentence-like. For example,Param.Is<T>
orValue.Is<T>
.Some notes, with code snippets, then the whole spec rewritten at the bottom.
The Scenario is your
Subject
The Subject can be the Scenario from the story. Plus, it gets rendered with your test run report (especially nice in the HTML report).
Don't waste time on "With" named base classes
MSpec's creator, Aaron Jensen, has reverted from using the "With" syntax altogether. Context class names do not show up for any reports, so avoid spending time inventing a meaningful name.
The Given is your spec class name
Name the concrete spec class after the Given in your story. Especially since the base class name isn't reported anywhere, you could be losing half your context in the report! You should also avoid putting the name of the system under test in context class names. This makes your contexts friendlier to refactoring the system under test.
Base spec classes should contain only general initialization
And are often unnecessary. They lead to separation of the Arrange and Act phases. Use a base class for common field initialization, like setting up mocked dependencies. But, you should not mock behavior in a base class. And you should not put context-specific information in the base class. In your example, the username/password. This way, you can create a second context with invalid credentials.
Fields in the concrete spec class should be private
It reduces the "ceremony" of the language in your test. You should place them below all of the MSpec specific delegates, as those parts of the spec tell most of the story.
The Spec Overhaul
The spec here is an excellent example of establishing a global context
MembershipContext
and inheriting it in a context specific to the spec (thus, the additionalEstablish
).