Reputation: 261
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".
Upvotes: 10
Views: 9367
Reputation: 2376
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.
System.DirectoryServices.AccountManagement
in your unit test projekt. Choose "Add Fakes Assembly".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".
Upvotes: 3
Reputation: 193
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
}
Upvotes: 13
Reputation: 136653
I'll answer that with the pithy phrase
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
Upvotes: 5
Reputation: 57242
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?
Upvotes: 1