Fake Captcha from commonlibnet with FakeItEasy and FluentValidation

拟墨画扇 提交于 2019-12-12 17:14:31

问题


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(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


回答1:


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.




回答2:


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");
    }
}


来源:https://stackoverflow.com/questions/5742425/fake-captcha-from-commonlibnet-with-fakeiteasy-and-fluentvalidation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!