简体   繁体   中英

Mocking UserPrincipal

I have a class that handles password changes and expiration checks for exchange mailboxes. I check for LastPasswordSet on a UserPrincipal.

Now what about TDD?

I want to check if my class handles the password checks correctly by writing some tests. But I cant get my head around how I could mock the UserPrincipal.FindByIdentity(principalContext, [some username]).

I'm about to write a method that return true/false if the password has been changed the last 90 days. So I would like to mock the UserPrincipal so I can set the LastPasswordSet return value in my tests just to check the logic I'm about to write for the "password needs change notification".

I realize this is an old post, but recently I ran into the same issue as the original poster and after reading the answer, I thought I would have to do the same thing. I don't want someone else to read this post and lose valuable time like I did, so I decided to truly answer this post.

After realizing that there is no easy way to wrap the UserPrincipal functionality nor rely on integration or end-to-end tests like suggested, I remembered there is a way to mock static classes. With that being said, below is exactly how to do it using Telerik JustMock .

private void MockUserPrincipal()
    {
        //Mock principal context
        var context = Mock.Create<PrincipalContext>((action) => action.MockConstructor());

        //Mock user principal
        var user = Mock.Create(() => new UserPrincipal(context));           

        //Mock the properties you need
        Mock.Arrange(() => user.Enabled).Returns(true);
        Mock.Arrange(() => user.UserPrincipalName).Returns("TestUser");
        Mock.Arrange(() => user.LastPasswordSet).Returns(DateTime.Now);

        //Mock any functions you need
        Mock.Arrange(() => user.IsAccountLockedOut()).Returns(false);

        //Setup static UserPrincipal class
        Mock.SetupStatic<UserPrincipal>();

        //Mock the static function you need
        Mock.Arrange(() => UserPrincipal.FindByIdentity(Arg.IsAny<PrincipalContext>(), Arg.AnyString)).Returns(user);  

        //Now calling UserPrincipal.FindByIdentity with any context and identity will return the mocked UserPrincipal
    }

I'll answer that with the pithy phrase

"Don't mock types you don't own"

couldn't find an authoritative blogpost to back that up. Sample link . Although it seems to be attributed to Joe Walnes.

UserPrincipal if I remember is a .Net framework class related to authentication. Mocking types that are out of your control (can change) can lead to fragile tests.

Instead discover what your design wants from UserPrincipal

  • find the role that UserPrincipal fulfills or implements indirectly via TDDing the clients
  • Mock that role in your unit tests and test all callers.
  • Have "integration tests" to ensure that your real implementation pushes the right buttons on UserPrincipal when invoked.
  • Rely on end-to-end / acceptance tests to find bugs that occur when all components are strung together.

Old post but there is a working example. Even though you never should test someone else's code you want to test your methods. And your methods might need data from a UserPrincipal that is returned from another method. Now say you need to check the LastPasswordSet property.

  1. Right click on the .dll System.DirectoryServices.AccountManagement in your unit test projekt. Choose "Add Fakes Assembly".
  2. Add this unit test

     [TestMethod] public async Task ActiveDirectoryUserFactory_CreateUserAsyncAndWhatYouExpect() { // Arrange using(ShimsContext.Create()) { var userPrincipal = new System.DirectoryServices.AccountManagement.Fakes.ShimUserPrincipal(); var baseUserPrincipal = new System.DirectoryServices.AccountManagement.Fakes.ShimAuthenticablePrincipal(userPrincipal); baseUserPrincipal.LastPasswordSetGet = () => DateTime.Now; // Mock the returned UserPrincipal to use our userPrincipal, here's for Moq _class.Setup(x => x.GetUserAsync("param")) .Returns(Task.FromResult<UserPrincipal>(userPrincipal)); // Act, your method that gets your shimUserPrincipal from _class.GetUserAsync in your _target class (I understood you got the UserPrincipal from external source) var user = await _target.YourMethod(); // Assert Assert.IsNull(user); } } // method that does the code you want to test public async Task<Object> YourMethod() { var user = await _class.GetUserAsync("param"); var lastLogin = user.LastPasswordSet; return new Object() } 

There are lot of sources out there for Shims so I let it be like this. Hope this helps someone who googles "mock UserPrincipal".

The UserPrincipal class is not really TDD friendly, I'm afraid.
What about wrapping the functionality you need in a class of yours and mock that instead?

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