开发者

Fake Captcha from commonlibnet with FakeItEasy and FluentValidation

I am using the Captcha class from commonlibrary (http://commonlibrarynet.codeplex.com/). My code works and everything but now I'm trying to write the unit test.

My validation rule is:

 RuleFor(x => x.CaptchaUserInput)
            .NotEmpty()
            .Must((x, captchaUserInput) => Captcha.IsCorrect(captchaUserInput, x.CaptchaGeneratedText))
            .WithMessage("Invalid captcha code");

In my set up code I tried to do the following:

A.CallTo(() => Captcha.IsCorrect()).Returns(true);

but I get the following error message:

SetUp : FakeItEasy.Configuration.FakeConfigurationException : 

The current proxy generator can not intercept the specified method for the following reason:
- Static methods can not be intercepted.


at FakeItEasy.Configuration.DefaultInterceptionAsserter.AssertThatMethodCanBeInterceptedOnInstance开发者_StackOverflow(Metho    dInfo method, Object callTarget)
at FakeItEasy.Configuration.FakeConfigurationManager.CallTo(Expression`1 callSpecification)
at ProdMaster.Hosts.Web.Tests.Unit.Controllers.AccountControllerTests.SetUp() in     AccountControllerTests.cs: line 44 

So the question really is how to fake static methods using FakeItEasy.

TIA,

David


There's no way to intercept static methods in FakeItEasy (and currently in no other opens source, free mocking framework for .Net). To be able to mock statics (and sealed classes) you would have to purchase either Typemock Isolator or Just Mock from Telerik.

Many developers consider statics to be code smell (in most cases). So the fact that open source mocking frameworks do not support this is seen as a good thing since it promotes better designs. A "golden rule" of mocking is "if you can't control it don't mock it" so the common way of going about the problem you've run into is to create a wrapper around the static calls. You test the interaction with this - mockable - wrapper. System.DateTime.Now is an example of a static that you'd often like to test against in your tests. To isolate your tests from this you'd do something like this:

public interface ISystemTimeProvider
{
    DateTime Now { get; }
}

public class DateTimeNowSystemTimeProvider
    : ISystemTimeProvider
{
    public DateTime Now
    {
        get
        {
            return DateTime.Now;
        }
    }
}

With the above interface and implementation your SUT would depend on the interface (for example through constructor injection). In your tests you would inject it with a fake (A.Fake<ISystemTimeProvider>()). The implementation of DateTimeSystemTimeProvider would never be unit tested, it's very low level and shouldn't need any tests really other than integration tests.

I'm not very familiar with the captcha library you're talking about so I'm not sure exactly how you would apply the above pattern in that case but I'm sure it can be done one way or another.


Similar to Patrik's solution, you can just pass a delegate into the constructor of your class that calls this static method.

So you'd setup a delegate in your default constructor pointing to Captcha.IsCorrect.

This delegate variable will be called within your fluentValidation code. While unit testing you will create a new constructor where you will set the delegate to point to your mock method. (in your case, just return true)

public class SomeValidator
{
    Func<string, string, bool> _captchaVerifier;

    public SomeValidator()
    {
        _captchaVerifier = Captcha.IsCorrect;
    }

    public SomeValidator(Func<string, string, bool> method)
    {
        _captchaVerifier = method;
    }

    public void Validate()
    { /* your code */
        RuleFor(x => x.CaptchaUserInput)
        .NotEmpty()
        .Must((x, captchaUserInput) => _captchaVerifier(captchaUserInput, x.CaptchaGeneratedText))
        .WithMessage("Invalid captcha code");
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜