简体   繁体   中英

How would I mock a UserPrincipal?

I'm trying to actually test my code for once, but mocking has always been (one of) my Achilles Heel(s).

I'm doing some stuff with AD, and want to test without actually touch it. Here's what I'm doing:

var userPrincipalMock = new Mock<UserPrincipal>();
userPrincipalMock.Setup(x => x.SamAccountName).Returns("somesamaccountname");
userPrincipalMock.Setup(x => x.EmployeeId).Returns("anemployeenumber");

But apparently UserPrincipal doesn't wanna give up control of a samaccount name that easily:

Message "Unsupported expression: x => x.SamAccountName\nNon-overridable members (here: Principal.get_SamAccountName) may not be used in setup / verification expressions."

Any of you lovely guys or gals know the right way to go about this?

It is impossible to test methods that aren't marked as virtual . For this reason only interfaces should be mocked. To solve your problem, you can create a wrapper:

interface IUserPrincipalWrapper
{
    string SamAccountName { get; set; }
    string EmployeeId { get; set; }
    void Delete();
    ... // Add all methods and properties of UserPrincipal that you need
}
class UserPrincipalWrapper : IUserPrincipalWrapper
{
    private UserPrincipal Implementation { get; }

    UserPrincipalWrapper(UserPrincipal implementation)
    {
       Implementation = implementation;
    }

    public string SamAccountName
    { 
     get => Implementation.SamAccountName; 
     set => Implementation.SamAccountName = value;
    }

    public string EmployeeId 
    { 
     get => Implementation.EmployeeId; 
     set => Implementation.EmployeeId = value;
    }

    public void Delete()
    {
        Implementation.Delete();
    }
    ...
    // Call or set everything to Implementation...
    // This is needed to create an interface around UserPrincipal, which you can mock
}
// Factory is needed for mocking `new` calls..
// as often times, you don't want to test that either
interface IUserPrincipalFactory
{
  IUserPrincipalWrapper Create(PrincipalContext context);
}
class UserPrincipalFactory : IUserPrincipalFactory
{
  public IUserPrincipalWrapper Create(PrincipalContext context)
  {
    var implementation = new UserPrincipal(context);
    return new UserPrincipalWrapper(implementation);
  }
}

Then in your tests you can mock everything:

// This is your mock
var userPrincipalMock = new Mock<IUserPrincipalWrapper>();

// You need factory for mocking `new UserPrincipal();` calls
var factoryMock = new Mock<IUserPrincipalWrapperFactory>();
factoryMock.Setup(factory => factory.Create(It.IsAny<PrincipalContext>())).Returns(userPrincipalMock.Object);

// Now it works :)
userPrincipalMock.Setup(x => x.SamAccountName).Returns("somesamaccountname");
userPrincipalMock.Setup(x => x.EmployeeId).Returns("anemployeenumber");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM