我是否正确写入了我的第一个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); }; }
上下文看起来不错。 我喜欢你用别名解决冲突的方式。 我会争辩Moq别名可以改进。 考虑一下类似的句子。 例如, Param.Is<T>
或Value.Is<T>
。
一些笔记,用代码片断,然后整个规范重写在底部。
情景是你的Subject
主题可以是故事中的情景。 此外,它会与您的testing运行报告(特别是在HTML报告中很好)呈现。
[Subject("Login Page")]
不要把时间浪费在“With”命名的基类上
MSpec的创build者Aaron Jensen 已经完全恢复使用“With”语法。 上下文类名不会显示任何报告,所以避免浪费时间发明一个有意义的名字。
public abstract class MembershipContext
给定是你的规范类名称
在您的故事中的Given后面命名具体的spec类。 特别是由于基类名称没有报告任何地方,你可能会失去报告中的一半的上下文! 您还应该避免将testing系统的名称放在上下文类名中。 这使得您的上下文更友好,可以重构被测系统。
public class When_an_existing_user_enters_valid_credentials
基本规范类应该只包含一般的初始化
而且往往是不必要的。 导致安排和行动阶段分离。 使用基类进行通用字段初始化,例如设置模拟的依赖关系。 但是,你不应该嘲笑基类中的行为。 你不应该把特定于上下文的信息放在基类中。 在你的例子中,用户名/密码。 这样,您可以使用无效凭据创build第二个上下文。
Establish context = () => { membership = new Mock<ISiteMembership>(); loginController = new LoginController(membership.Object); };
具体规范类中的字段应该是私有的
它减less了testing中的语言“仪式”。 您应该将它们放在所有MSpec特定代表的下方,因为规范的这些部分讲述了大部分故事。
static ActionResult result;
规范检修
这里的规范是一个很好的例子,build立一个全局上下文MembershipContext
,并在特定的上下文中inheritance它(因此,额外的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; }