ASP.NET MVC5 校验Captcha的控制器方法单元测试如何设置Captcha有效
解决方案
你可以通过以下两种常用方案解决单元测试中的验证码校验问题:
方案1:不修改原有业务代码,伪造请求上下文适配CaptchaMVC校验逻辑
CaptchaMVC提供的IsCaptchaValid扩展方法默认从当前Http上下文的Form参数、Session存储中读取验证码信息做匹配,你只需要在单元测试中给控制器实例注入伪造的Http上下文,模拟验证码校验通过的条件即可:
[TestMethod] public void TestFoo() { var myMod = new MyModel(); myMod.val1 = "0123456789"; var controller = new MyController(); // 伪造Http上下文,设置正确的验证码参数(示例使用Moq框架,也可替换为你常用的模拟工具) var httpContext = new Mock<HttpContextBase>(); var session = new Mock<HttpSessionStateBase>(); // CaptchaMVC默认用"CaptchaCode"作为Session存储键,设置和请求参数一致即可通过校验 const string testCaptchaValue = "test123"; session.Setup(s => s["CaptchaCode"]).Returns(testCaptchaValue); httpContext.Setup(c => c.Session).Returns(session.Object); httpContext.Setup(c => c.Request.Form["CaptchaInput"]).Returns(testCaptchaValue); // 给控制器绑定伪造上下文 controller.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), controller); var result = controller.Foo(myMod); Assert.IsNotNull(result); }
如果你没有使用Moq框架,也可以用.NET自带的
FakeHttpContext相关实现类替代上述模拟逻辑。
方案2:抽象校验逻辑(更符合单元测试最佳实践)
如果你的项目后续需要频繁测试带验证码的接口,建议将验证码校验逻辑抽离为独立接口,通过依赖注入的方式注入到控制器中,单元测试时直接传入返回true的模拟实现即可:
1. 定义抽象接口
public interface ICaptchaService { bool Validate(string errorMsg); }
2. 实现真实业务逻辑
public class CaptchaService : ICaptchaService { private readonly Controller _controller; public CaptchaService(Controller controller) { _controller = controller; } public bool Validate(string errorMsg) { return _controller.IsCaptchaValid(errorMsg); } }
3. 改造原有控制器
public class MyController : Controller { private readonly ICaptchaService _captchaService; // 构造函数注入,正式环境传入真实实现,单元测试传入模拟实现 public MyController(ICaptchaService captchaService = null) { _captchaService = captchaService ?? new CaptchaService(this); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Foo(MyModel model){ if(ModelState.IsValid){ if(_captchaService.Validate("Error msg")){ //执行业务逻辑 } } var mod = this.GetMyModel(); return this.View("Index", mod); } }
4. 改造后单元测试代码
[TestMethod] public void TestFoo() { var myMod = new MyModel(); myMod.val1 = "0123456789"; // 模拟验证码校验永远通过的服务实现 var mockCaptcha = new Mock<ICaptchaService>(); mockCaptcha.Setup(c => c.Validate(It.IsAny<string>())).Returns(true); var controller = new MyController(mockCaptcha.Object); var result = controller.Foo(myMod); Assert.IsNotNull(result); }
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

