【问题标题】:Simplest way to mock properties of PostSharp attribute模拟 PostSharp 属性的最简单方法
【发布时间】:2012-01-19 04:18:54
【问题描述】:

我正在使用 PostSharp 方法属性对我的 WCF 服务进行授权和审核。它工作正常,但现在我正试图让我的单元测试与属性一起工作,并且正在努力寻找一种方法来模拟和注入属性上的属性。

我的属性如下。

[Serializable]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class AuthoriseAndAuditAttribute : OnMethodBoundaryAspect
{
    private static ILog logger = AppState.logger;

    private static Ninject.IKernel _kernel = MyKernel.Kernel;

    private UserRoleTypesEnum _requiredRole = UserRoleTypesEnum.None;

    [Inject]
    public IServiceAuthToken _serviceAuthToken { get; set; }

    [Inject]
    public UserSessionDataLayer _userSessionDataLayer { get; set; }

    public AuthoriseAndAuditAttribute(UserRoleTypesEnum role = UserRoleTypesEnum.None)
    {
        _requiredRole = role;
        _kernel.Inject(this);
    }

    public override void OnEntry(MethodExecutionArgs args)
    {
        // Get the user's session from cookie.
        UserSession userSession = GetUserSession();

        // Check that user is in the required role.
        bool isAuthorised = (_requiredRole == UserRoleTypesEnum.None || (userSession != null && userSession.Roles.Contains(_requiredRole)));

        if (!isAuthorised)
        {
            logger.Warn("Not authorised for " + args.Method.Name + ".");
            throw new UnauthorizedAccessException();
        }
        else if (userSession != null)
        {
            Thread.CurrentPrincipal = new MyPrincipal(userSession);
        }
    }

    private UserSession GetUserSession()
    {
        if (_serviceAuthToken != null)
        {
            string sessionID = _serviceAuthToken.GetSessionID();

             if (!sessionID.IsNullOrBlank())
             {
                 return _userSessionDataLayer.GetForSessionID(sessionID);
             }
         }

         return null;
     }
}

我有一个设置 Ninject 内核的单例类:

public class MyKernel
{
    public static StandardKernel Kernel { get; set; }

    static MyKernel()
    {
        Kernel = new StandardKernel();
        Kernel.Bind<IServiceAuthToken>().To<ServiceAuthToken>();
        Kernel.Bind<UserSessionDataLayer>().To<UserSessionDataLayer>();
    }
}

在我的 WCF 服务中,我使用 PostSharp 属性,如下所示:

[AuthoriseAndAudit(UserRoleTypesEnum.Operator)]
public JSONResult<bool> IsAliveAuthorised()
{
   return new JSONResult<bool>() { Success = true, Result = true };
}

在我的单元测试中,我使用 RhinoMocks 来尝试模拟属性中的两个 DI 属性。

 [TestMethod]
 public void IsAliveAuthorisedIsAuthorisedTest()
 {
     var mockServiceAuthToken = MockRepository.GenerateStrictMock<ServiceAuthToken>();
     mockServiceAuthToken.Stub(x => x.GetSessionID()).Return("x");
     var mockUserSessionDataLayer = MockRepository.GenerateStrictMock<UserSessionDataLayer>();
     mockUserSessionDataLayer.Stub(x => x.GetForSessionID(Arg<string>.Is.Anything)).Return(new UserSession());

     MyKernel.Kernel.Bind<ServiceAuthToken>().ToConstant(mockServiceAuthToken);
     MyKernel.Kernel.Bind<UserSessionDataLayer>().ToConstant(mockUserSessionDataLayer);

     var service = new MyService();
     Assert.IsTrue(service.IsAliveAuthorised().Result);
}

我遇到的问题是单元测试中的模拟对象永远不会被设置为属性的属性。我做错了什么,或者相反,有没有更好的方法对 PostSharp 属性进行单元测试?还要记住,我真的想尽量减少 Ninject DI 的使用。

【问题讨论】:

  • 那么属性分配了什么?实际的对象,还是它们为空?
  • 不,它们不为空。 _kernel.Inject(this) 调用设置两个属性对象。我试图用我的单元测试做的是改变 ninject 内核用来设置它们的对象,这就是不工作的位。
  • 对,所以您希望 Mock 对象存在,但“真实”对象仍在显示?
  • 是的,就是这样,虽然我是“希望”而不是“期待”:)。
  • Ninject 是您项目的关键部分还是仅用于单元测试目的?

标签: wcf unit-testing ninject rhino-mocks postsharp


【解决方案1】:

不要在属性上使用 [Inject] 属性,而是像这样重新定义它们:

    public IServiceAuthToken _serviceAuthToken { get { return _kernel.Get<IServiceAuthToken>(); } }

    public UserSessionDataLayer _userSessionDataLayer { get { return _kernel.Get<UserSessionDataLayer>(); } }

另外,在您的测试方法中,您需要重新绑定(还要注意,您在第一次绑定中使用的是具体类型 ServiceAuthToken 而不是接口 IServiceAuthToken):

MyKernel.Kernel.Rebind<IServiceAuthToken>().ToConstant(mockServiceAuthToken);
MyKernel.Kernel.Rebind<UserSessionDataLayer>().ToConstant(mockUserSessionDataLayer);

【讨论】:

  • 这与我最终所做的非常接近。唯一的区别是我在 PostSharp OnEntry 方法的开头调用 kernel.Inject 而不是在每个属性上调用 kernel.Get。而且我还在我的单元测试初始化​​中做 tehe kernel.Rebind。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-26
  • 2022-02-04
  • 2020-07-07
相关资源
最近更新 更多