5

I am writing some unit tests for an extension method I have written on IPrincipal. To assist, I have created a couple of helper classes (some code for not-implemented members of the interfaces has been omitted for brevity):

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!!!
}

However, the Name property in the IIdentity interface is read-only (the IIDentity interface specifies a getter but not a setter for the Name property).

How can I set the Name property in my stub object for testing purposes if the interface has defined it as a read-only property?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • Constructor? i.e `IIdentityStub` will have a parameterized constructor that takes Name as parameter. – shahkalpesh Mar 29 '10 at 18:05
  • Did your "BZZZT" refer to a compile error? I was able to compile your sample just fine (w/semi-colons on the Identity property, that is). – micahtan Mar 29 '10 at 18:27
  • @micahtan: Yes, but when you try to write a test against it, and set the value of `Name` in the test, the compiler will complain that `Name` is read-only, because the `Name` property in `IIDentity` does not have a setter defined. – Robert Harvey Mar 29 '10 at 22:35
  • I was thinking of setting IPrincipalStub.Identity to an instance of IIdentityStub that you construct (thus taking advantage of the setter) instead of using the constructor-created field. I guess it depends on what you want your setup code to look like in your unit tests. – micahtan Mar 30 '10 at 02:29
  • @Micahtan: I wound up putting a constructor in `IPrincipalStub` that accepted the `Name` as a string, and passed it along to the `IIDentityStub` constructor that also accepted the name as a string. Eventually, I will be doing everything in Moq, though. – Robert Harvey Mar 30 '10 at 03:30

3 Answers3

4

You're using the auto-properties feature of C# but instead you should go the manual route and create a backing field for the property. Once you have a backing field you can set its value in the constructor (or make it a public field and set it after you have the object, but this is a little uglier).

public class IIdentityStub : IIdentity{
    private string _name;

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

    public string Name { get { return _name; } }
}
Restore the Data Dumps
  • 38,967
  • 12
  • 96
  • 122
2

I agree with juharr - use a mocking/isolation framework. I'd recommend Moq.

The following will print "Robert":

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);
        }
    }
}

EDIT: But if you want to do it by hand...

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; }
    }
}

(The above is not a unit test, just an example of hand-rolled stubs using a bit of dependency injection.)

TrueWill
  • 25,132
  • 10
  • 101
  • 150
1

I recommend using a Mock library like NMock

juharr
  • 31,741
  • 4
  • 58
  • 93