我是单元测试和模拟概念的新手.我想弄清楚如何为下面的基本开箱即用用户注册代码编写一个好的测试用例:
[HttpPost] public ActionResult Register(RegisterModel model) { if (ModelState.IsValid) { // Attempt to register the user MembershipCreateStatus createStatus; Membership.CreateUser(model.UserName,model.Password,model.Email,null,true,out createStatus); if (createStatus == MembershipCreateStatus.Success) { FormsAuthentication.SetAuthCookie(model.UserName,false /* createPersistentCookie */); return RedirectToAction("Index","Home"); } else { ModelState.AddModelError("",ErrorCodeToString(createStatus)); } } // If we got this far,something Failed,redisplay form return View(model); }
以下是我需要您的意见/帮助的一些具体要点:
解决方法
你的代码有问题.您的操作取决于静态方法:Membership.CreateUser.正如您所知,静态方法是用于单元测试的PITA.
所以你可以通过引入一个抽象级别来削弱耦合:
public interface IMyService { MembershipCreateStatus CreateUser(string username,string password,string email); }
然后有一些使用当前成员资格提供者的实现:
public class MyService: IMyService { public MembershipCreateStatus CreateUser(string username,string email) { MembershipCreateStatus status; Membership.CreateUser(username,password,email,out status); return status; } }
最后是控制器:
public class AccountController : Controller { private readonly IMyService _service; public AccountController(IMyService service) { _service = service; } [HttpPost] public ActionResult Register(RegisterModel model) { if (ModelState.IsValid) { // Attempt to register the user var status = _service.CreateUser(model.UserName,model.Email); if (status == MembershipCreateStatus.Success) { FormsAuthentication.SetAuthCookie(model.UserName,false /* createPersistentCookie */); return RedirectToAction("Index","Home"); } else { ModelState.AddModelError("",ErrorCodeToString(createStatus)); } } // If we got this far,redisplay form return View(model); } }
好了,既然我们已经削弱了耦合,我们可以使用模拟框架来模拟单元测试中的服务并使其变得微不足道.
例如,使用Rhino Mocks,您可以创建以下测试以涵盖2个故障情况:
[TestMethod] public void Register_Action_Should_Redisplay_View_If_Model_Is_Invalid() { // arrange var sut = new AccountController(null); var model = new RegisterModel(); sut.ModelState.AddModelError("","invalid email"); // act var actual = sut.Register(model); // assert Assert.IsInstanceOfType(actual,typeof(ViewResult)); var viewResult = actual as ViewResult; Assert.AreEqual(model,viewResult.Model); } [TestMethod] public void Register_Action_Should_Redisplay_View_And_Add_Model_Error_If_Creation_Fails() { // arrange var service = MockRepository.GenerateStub<IMyService>(); service .Stub(x => x.CreateUser(null,null)) .IgnoreArguments() .Return(MembershipCreateStatus.InvalidEmail); var sut = new AccountController(service); var model = new RegisterModel(); // act var actual = sut.Register(model); // assert Assert.IsInstanceOfType(actual,viewResult.Model); Assert.IsFalse(sut.ModelState.IsValid); }
最后的测试是成功案例.我们仍然有一个问题.问题是以下行:
FormsAuthentication.SetAuthCookie(model.UserName,false);