简体   繁体   English

嘲笑UserPrincipal

[英]Mocking UserPrincipal

I have a class that handles password changes and expiration checks for exchange mailboxes. 我有一个类来处理密码更改和交换邮箱的到期检查。 I check for LastPasswordSet on a UserPrincipal. 我在UserPrincipal上检查LastPasswordSet。

Now what about TDD? 那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]). 但我无法理解我如何模拟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. 如果密码在过去90天内被更改,我即将编写一个返回true / false的方法。 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". 所以我想模拟UserPrincipal,这样我就可以在我的测试中设置LastPasswordSet返回值,只是为了检查我要编写的“密码需求更改通知”的逻辑。

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. 在意识到没有简单的方法来包装UserPrincipal功能,也不依赖于像建议的集成或端到端测试之后,我记得有一种模拟静态类的方法。 With that being said, below is exactly how to do it using Telerik JustMock . 话虽如此,下面是使用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. 虽然它似乎归功于Joe Walnes。

UserPrincipal if I remember is a .Net framework class related to authentication. UserPrincipal如果我记得是一个与身份验证相关的.Net框架类。 Mocking types that are out of your control (can change) can lead to fragile tests. 模拟不受您控制(可能更改)的类型可能导致脆弱的测试。

Instead discover what your design wants from UserPrincipal 而是从UserPrincipal发现您的设计需要什么

  • find the role that UserPrincipal fulfills or implements indirectly via TDDing the clients 通过TDDing客户端找到UserPrincipal间接实现或实现的角色
  • 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. 进行“集成测试”以确保您的实际实现在调用时在UserPrincipal上按下正确的按钮。
  • 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. 并且您的方法可能需要来自另一个方法返回的UserPrincipal数据。 Now say you need to check the LastPasswordSet property. 现在说你需要检查LastPasswordSet属性。

  1. Right click on the .dll System.DirectoryServices.AccountManagement in your unit test projekt. 右键单击单元测试项目中的.dll System.DirectoryServices.AccountManagement 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. Shims有很多资源,所以我让它像这样。 Hope this helps someone who googles "mock UserPrincipal". 希望这可以帮助谷歌搜索“模拟UserPrincipal”的人。

The UserPrincipal class is not really TDD friendly, I'm afraid. 我担心UserPrincipal类不是TDD友好的。
What about wrapping the functionality you need in a class of yours and mock that instead? 如何将您需要的功能包装在您的类中并进行模拟呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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