2

我使用commonlibrary(http://commonlibrarynet.codeplex.com/)的验证码类。我的代码工作和一切,但现在我试图编写单元测试。FakeItEasy和FluentValidation从commonlibnet伪造的验证码

我的验证规则是:

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,

大卫

回答

7

有没有办法拦截静态方法FakeItEasy(在没有其他,目前开源,.net的免费模拟框架)。为了能够模拟静态(和密封类),你必须从Telerik购买Typemock Isolator或Just Mock。

许多开发人员认为静态是代码异味(在大多数情况下)。因此,开源嘲讽框架不支持这一事实被认为是一件好事,因为它促进了更好的设计。嘲笑的“黄金法则”是“如果你不能控制它,不要嘲笑它”,所以解决你遇到的问题的常见方式是创建一个围绕静态调用的包装。你测试与这个 - mockable-wrapper的交互。 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的实现永远不会被单元测试,它的级别非常低,除了集成测试外,不需要任何测试。

我不是很熟悉你正在谈论的captcha库,所以我不确定你在这种情况下如何应用上述模式,但我确信它可以这样或那样完成。

+0

谢谢你在这里和通过电子邮件的答案。非常感谢。我并没有试图嘲笑Captcha控制,而是扼杀了它。从Roy Osherove关于单元测试的书中我已经阅读和理解的内容可以看出,这是我应该做的,因为它是一种外部依赖性,不应该使我的测试失败。无论如何,我相信我已经理解了你的观点,并且会尝试调整提供给Captcha控件的代码。再次感谢你。大卫 – DavidS 2011-04-24 12:10:34

1

与Patrik的解决方案类似,您可以将委托传递到调用此静态方法的类的构造函数中。

所以你会在默认构造函数中设置一个指向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"); 
    } 
}