您的代码存在问题,您的操作依赖于静态方法:Membership.CreateUser
。正如您所知,静态方法难以进行单元测试。
因此,您可以通过引入一个抽象层来降低耦合度:
public interface IMyService
{
MembershipCreateStatus CreateUser(string username, string password, string email);
}
然后有一些实现将使用当前的成员资格提供程序:
public class MyService: IMyService
{
public MembershipCreateStatus CreateUser(string username, string password, string email)
{
MembershipCreateStatus status;
Membership.CreateUser(username, password, email, null, null, true, null, 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)
{
var status = _service.CreateUser(model.UserName, model.Password, model.Email);
if (status == MembershipCreateStatus.Success)
{
FormsAuthentication.SetAuthCookie(model.UserName, false );
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", ErrorCodeToString(createStatus));
}
}
return View(model);
}
}
好的,现在我们已经减少了耦合,可以使用模拟框架来模拟单元测试中的服务并使其变得简单。
例如,使用Rhino Mocks,您可以创建以下测试用例来覆盖2个失败案例:
[TestMethod]
public void Register_Action_Should_Redisplay_View_If_Model_Is_Invalid()
{
var sut = new AccountController(null);
var model = new RegisterModel();
sut.ModelState.AddModelError("", "invalid email");
var actual = sut.Register(model);
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()
{
var service = MockRepository.GenerateStub<IMyService>();
service
.Stub(x => x.CreateUser(null, null, null))
.IgnoreArguments()
.Return(MembershipCreateStatus.InvalidEmail);
var sut = new AccountController(service);
var model = new RegisterModel();
var actual = sut.Register(model);
Assert.IsInstanceOfType(actual, typeof(ViewResult));
var viewResult = actual as ViewResult;
Assert.AreEqual(model, viewResult.Model);
Assert.IsFalse(sut.ModelState.IsValid);
}
最后的测试是成功案例。我们仍然有一个问题。问题出在以下这行代码:
FormsAuthentication.SetAuthCookie(model.UserName, false)
这是什么?这是一个静态方法调用。因此,我们需要像处理成员身份提供程序一样处理它,以减弱控制器和表单认证系统之间的耦合。