2010-03-29 45 views
5

我正在为写在IPrincipal上的扩展方法写一些单元测试。为了帮助,我已经创建了几个辅助类的(一些代码,接口没有实现的成员已为简洁起见省略):如何为包含只读成员的接口创建单元测试存根?

public class IPrincipalStub : IPrincipal 
{ 
    private IIdentity identityStub = new IIdentityStub(); 

    public IIdentity Identity 
    { 
     get { return identityStub; } 
     set { identityStub = value; } 
    } 
} 

public class IIdentityStub : IIdentity 
{ 
    public string Name { get; set; } // BZZZT!!! 
} 

然而,在IIdentity接口Name属性为只读( IIDentity接口为Name属性指定了一个getter而不是setter)。

如果接口已将其定义为只读属性,如何在存根对象中设置Name属性以用于测试目的?

+0

构造函数?即'IIdentityStub'将有一个参数化的构造函数,它将Name作为参数。 – shahkalpesh 2010-03-29 18:05:46

+0

您的“BZZZT”引用了编译错误吗?我能够很好地编译你的示例(在标识属性上带有分号,就是这样)。 – micahtan 2010-03-29 18:27:44

+0

@micahtan:是的,但是当您尝试针对它编写测试,并在测试中设置Name时,编译器会抱怨Name是只读的,因为'Name'属性在' IIDentity'没有定义setter。 – 2010-03-29 22:35:41

回答

3

您正在使用C#的自动属性功能,但您应该去手动路由并为该属性创建一个后台字段。一旦你有一个支持领域,你可以在构造函数中设置它的值(或者将其设置为公共字段并在拥有该对象后进行设置,但这有点丑陋)。

public class IIdentityStub : IIdentity{ 
    private string _name; 

    public IIdentityStub(string name){ 
     _name = name; 
    } 

    public string Name { get { return _name; } } 
} 
+0

如果通过构造函数无法设置该值,则说明设计存在问题。 – 2010-03-29 18:11:33

+0

非常好,谢谢。 – 2010-03-29 18:21:10

+0

@罗伯特哈维:没问题,先生。 – 2010-03-29 18:22:21

1

我建议使用一个模拟库像NMock

+1

是的,但我想我最好先学习如何写自己的存根。 – 2010-03-29 18:19:48

2

我同意juharr - 用嘲讽/隔离框架。我建议Moq

下将打印 “罗伯特”:

using System; 
using System.Security.Principal; 
using Moq; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var mockIdentity = new Mock<IIdentity>(); 
      var mockPrincipal = new Mock<IPrincipal>(); 

      mockIdentity.SetupGet(x => x.Name).Returns("Robert"); 
      mockPrincipal.SetupGet(x => x.Identity).Returns(mockIdentity.Object); 

      IPrincipal myStub = mockPrincipal.Object; 

      Console.WriteLine(myStub.Identity.Name); 
     } 
    } 
} 

编辑:但是,如果你想通过做手工......

using System; 
using System.Security.Principal; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main() 
     { 
      IIdentity identity = 
       new IdentityStub 
        { 
         Name = "Robert", 
         AuthenticationType = "Kerberos", 
         IsAuthenticated = true 
        }; 

      IPrincipal principal = new PrincipalStub(identity); 

      Console.WriteLine(principal.Identity.Name); // Robert 
      Console.WriteLine(principal.IsInRole(PrincipalStub.ValidRole)); // True 
      Console.WriteLine(principal.IsInRole("OtherRole")); // False 
     } 
    } 

    public class PrincipalStub : IPrincipal 
    { 
     public const string ValidRole = "TestRole"; 

     public PrincipalStub(IIdentity identity) 
     { 
      Identity = identity; 
     } 

     public IIdentity Identity { get; private set; } 

     public bool IsInRole(string role) 
     { 
      return role == ValidRole; 
     } 
    } 

    public class IdentityStub : IIdentity 
    { 
     public string Name { get; set; } 
     public string AuthenticationType { get; set; } 
     public bool IsAuthenticated { get; set; } 
    } 
} 

(以上为一单元测试,只是使用一点依赖注入的手动存根的例子。)