#unit-testing #captcha #fluentvalidation #fakeiteasy #common-library
#модульное тестирование #капча #fluentvalidation #поддельная капча #общая библиотека
Вопрос:
Я использую класс Captcha из commonlibrary (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,
Дэвид
Ответ №1:
В FakeItEasy нет способа перехватить статические методы (и в настоящее время ни в каком другом бесплатном фреймворке с открытым исходным кодом для создания макетов для .Net). Чтобы иметь возможность имитировать статику (и закрытые классы), вам нужно будет приобрести либо Typemock Isolator, либо просто макет от Telerik.
Многие разработчики считают, что статика — это запах кода (в большинстве случаев). Поэтому тот факт, что фреймворки с открытым исходным кодом, имитирующие фреймворки, не поддерживают это, рассматривается как хорошая вещь, поскольку это способствует улучшению дизайна. «Золотое правило» издевательства гласит: «если вы не можете это контролировать, не издевайтесь над этим», поэтому обычный способ решения проблемы, с которой вы столкнулись, — создать оболочку вокруг статических вызовов. Вы тестируете взаимодействие с этой — поддельной-оболочкой. Система.Дата и время.Теперь приведен пример статики, с которой вы часто хотели бы протестировать в своих тестах. Чтобы изолировать ваши тесты от этого, вы бы сделали что-то вроде этого:
public interface ISystemTimeProvider
{
DateTime Now { get; }
}
public class DateTimeNowSystemTimeProvider
: ISystemTimeProvider
{
public DateTime Now
{
get
{
return DateTime.Now;
}
}
}
С вышеупомянутым интерфейсом и реализацией ваш SUT будет зависеть от интерфейса (например, через внедрение конструктора). В ваших тестах вы бы внедрили в нее поддельную ( A.Fake<ISystemTimeProvider>()
). Реализация DateTimeSystemTimeProvider никогда не будет проходить модульное тестирование, она очень низкого уровня и не должна нуждаться в каких-либо тестах, действительно отличных от интеграционных тестов.
Я не очень знаком с библиотекой captcha, о которой вы говорите, поэтому я не уверен, как именно вы применили бы приведенный выше шаблон в этом случае, но я уверен, что это можно сделать тем или иным способом.
Комментарии:
1. Спасибо за ваш ответ здесь и по электронной почте. Очень признателен. Я не пытался издеваться над элементом управления Captcha, а скорее заглушал его. Из того, что я прочитал и понял из книги Роя Ошерова по модульному тестированию, это то, что я должен был сделать, поскольку это внешняя зависимость, которая не должна была провалить мой тест. В любом случае, я полагаю, что понял ваши замечания, и я попытаюсь адаптировать предоставленный код к элементу управления Captcha. Еще раз благодарю вас. Дэвид
Ответ №2:
Аналогично решению Patrik, вы можете просто передать делегат в конструктор вашего класса, который вызывает этот статический метод.
Итак, вы бы настроили делегат в вашем конструкторе по умолчанию, указывающий на капчу.Исправлено.
Эта переменная делегата будет вызываться в вашем коде 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");
}
}