How I can test the following Action of the controller:
public ActionResult Edit(User usr)
{
if (!Microsoft.Web.Helpers.ReCaptcha.Validate(ConfigurationManager.AppSettings["reCaptchaPrivate"].ToString()))
{
ModelState.AddModelError("reCaptcha", PPRR.App_LocalResources.Global.ErrorFillReCaptcha);
return PartialView("Wrong", usr);
}
if (ModelState.IsValid)
{code..... }}
I would start by abstracting the Captcha validation code:
public interface ICaptchaValidator
{
bool Validate();
}
and then have my controller look like this:
public class FooController: Controller
{
private readonly ICaptchaValidator _validator;
public FooController(ICaptchaValidator validator)
{
_validator = validator;
}
public ActionResult Edit(User usr)
{
if (!_validator.Validate())
{
ModelState.AddModelError("reCaptcha", PPRR.App_LocalResources.Global.ErrorFillReCaptcha);
return PartialView("Wrong", usr);
}
...
}
}
Now you have weaken the coupling between your controller and the way those captchas are validated. That's a good thing as it makes your controller action far easier to unit test. We have successfully made our controller independent of the actual way validation is implemented.
Now just pick a mocking framework such as Rhino Mocks, Moq, NSubstitute and in your unit test inject a stubbed validator into this controller so that you can define behaviors on it.
Personally I would recommend you MvcContrib.TestHelper (which is based on Rhino Mocks) to test your ASP.NET MVC applications. It has many built-in goodies for mocking the HttpContext and make unit testing easy.
Here's an example of how the validation failure case could be tested:
[TestMethod]
public void FooController_Edit_Action_Should_Return_The_Wrong_Partial_If_Captcha_Validation_Fails()
{
// arrange
var validatorStub = MockRepository.GenerateStub<ICaptchaValidator>();
var sut = new HomeController(validatorStub);
var user = new User();
validatorStub.Stub(x => x.Validate()).Return(false);
// act
var actual = sut.Edit(user);
// assert
actual
.AssertPartialViewRendered()
.ForView("Wrong")
.WithViewData<User>()
.Equals(user);
Assert.IsFalse(sut.ModelState.IsValid);
}
As an alternative to Darin's answer, I've previously used a custom ActionFilter that processes the captcha and adds the error to the ModelState. It worked really well and meant that the captcha code wasn't part of the action method itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With