Поддельная капча из обычной библиотеки с помощью FakeItEasy и FluentValidation - PullRequest
2 голосов
/ 21 апреля 2011

Я использую класс Captcha из обычной библиотеки (http://commonlibrarynet.codeplex.com/). Мой код работает и все, но сейчас я пытаюсь написать модульный тест.

Мое правило проверки:

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

В своем коде настройки я попытался сделать следующее:

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

, но получаю следующее сообщение об ошибке:

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 

Так что вопрос на самом деле заключается в том, как подделать статические методыиспользуя FakeItEasy.

TIA,

David

Ответы [ 2 ]

7 голосов
/ 23 апреля 2011

Нет способа перехватить статические методы в FakeItEasy (и в настоящее время ни в каком другом бесплатном фреймворке с открытым исходным кодом для .Net). Чтобы иметь возможность имитировать статику (и запечатанные классы), вам придется купить Typemock Isolator или Just Mock у Telerik.

Многие разработчики считают статику запахом кода (в большинстве случаев). Поэтому тот факт, что фреймворки с открытым исходным кодом не поддерживают это, рассматривается как хорошая вещь, поскольку он способствует созданию более совершенных проектов. «Золотое правило» насмешек - «если вы не можете управлять им, не издевайтесь над ним», поэтому наиболее распространенный способ решить проблему, с которой вы столкнулись, - создать оболочку для статических вызовов. Вы проверяете взаимодействие с этой - насмешливой - оберткой. System.DateTime.Now - это пример статики, которую вы часто хотели бы проверить в своих тестах. Чтобы изолировать ваши тесты от этого, вы должны сделать что-то вроде этого:

public interface ISystemTimeProvider
{
    DateTime Now { get; }
}

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

С указанным выше интерфейсом и реализацией ваша SUT будет зависеть от интерфейса (например, через внедрение конструктора). В ваших тестах вы вводите его с подделкой (A.Fake<ISystemTimeProvider>()). Реализация DateTimeSystemTimeProvider никогда не будет тестироваться модульно, она очень низкого уровня и не требует никаких других тестов, кроме интеграционных тестов.

Я не очень знаком с библиотекой капчи, о которой вы говорите, поэтому я не уверен, как именно вы примените вышеуказанный шаблон в этом случае, но я уверен, что это можно сделать так или иначе.

1 голос
/ 05 ноября 2014

Подобно решению Патрика, вы можете просто передать делегат в конструктор вашего класса, который вызывает этот статический метод.

Таким образом, вы настроите делегата в конструкторе по умолчанию, указывающем на Captcha.IsCorrect.

Эта переменная-делегат будет вызываться из вашего кода fluentValidation. Во время модульного тестирования вы создадите новый конструктор, в котором вы установите делегат, указывающий на ваш метод макета. (в вашем случае просто верните 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");
    }
}
...