我试图模拟在.net core中使用Identity生成电子邮件令牌
本文关键字:Identity 令牌 电子邮件 模拟 core net | 更新日期: 2023-09-27 18:11:39
我正试图在。net核心中做一些嘲弄,特别是围绕身份。我已经创建了一个。net核心类库项目,我有信心我有所有正确的参考。我试图模拟的第一件事是身份方法GenerateConfirmationTokenAsync方法,因为我试图模拟注册用户的设置。这是目前为止我在我的测试类中使用moq和Xunit的内容。
public class ServiceTests
{
private readonly string _email;
private readonly string _subject;
private readonly string _message;
private readonly Mock<IAccountService> _accountService;
private readonly ApplicationUser _applicationUser;
private readonly Mock<VisualJobsDbContext> _identityDbContext;
public ServiceTests()
{
_email = "me@gmail.com";
_subject = "test from me";
_message = "hello I got to you";
_accountService = new Mock<IAccountService>();
_applicationUser = new ApplicationUser { UserName = _email, Email = _email };
_identityDbContext = new Mock<VisualJobsDbContext>();
}
[Fact]
public async Task GenerateConfirmationToken()
{
Mock<DbSet<ApplicationUser>> userMock = DbSetMock.Create(_applicationUser);
var register = await _accountService.Object.Register(userMock.Object.First(), "password");
var token = await _accountService.Object.GenerateEmailConfirmationTokenAsync(userMock.Object.First());
Assert.NotNull(token);
}
我的ApplicationUser类继承了IdentityUser 'register'和'token'总是空的。如果我查看userMock,我也看不到一个令牌
为了测试模拟,首先需要设置它做一些事情,否则它只是一个没有实现的空接口。
在您的特定情况下,似乎您根本不需要mock。创建ApplicationUser
用户的实例,从中创建DbSet模拟,然后从中取出第一个对象。这与直接将ApplicationUser
实例传递给您的服务相同。
相反,您正在将ApplicationUser
传递给mock,它根本没有实现,因此实际上您根本没有测试任何内容。
public class ServiceTests
{
private readonly string _email;
private readonly string _subject;
private readonly string _message;
private readonly Mock<IAccountService> _accountService;
private readonly ApplicationUser _applicationUser;
private readonly Mock<VisualJobsDbContext> _identityDbContext;
public ServiceTests()
{
_email = "me@gmail.com";
_subject = "test from me";
_message = "hello I got to you";
_applicationUser = new ApplicationUser { UserName = _email, Email = _email };
}
[Fact]
public async Task GenerateConfirmationToken()
{
// Does it have dependencies? If yes, you may need to mock them
var _accountService = new AccountService(.../*mocked dependencies*/);
var register = await _accountService.Register(_applicationUser, "password");
var token = await _accountService.GenerateEmailConfirmationTokenAsync(userMock.Object.First());
Assert.NotNull(token);
}
现在,这取决于你在Register
和GenerateEmailConfirmationTokenAsync
中有什么样的逻辑,如果你需要moq,你在AccountService
中有哪些依赖关系。
让我们假设你有一个名为TokenGenerator
的服务,它实现了ITokenGenerator
接口。
public class ServiceTests
{
private readonly string _email;
private readonly string _subject;
private readonly string _message;
private readonly ApplicationUser _applicationUser;
private readonly Mock<ITokenGenerator> _tokenGenerator;
public ServiceTests()
{
_email = "me@gmail.com";
_subject = "test from me";
_message = "hello I got to you";
_applicationUser = new ApplicationUser { UserName = _email, Email = _email };
_tokenGenerator = Mock<ITokenGenerator>();
}
[Fact]
public async Task GenerateConfirmationToken()
{
// #### Setup ####
// Reads: If GenerateToken method is called with the **exact** same instance as the user passed to the service
_tokenGenerator.Setup(t => t.GenerateToken(It.Is(user)))
// then return "abc123456" as token
.Returns("abcd123456")
// Verify that the method is called with the exact conditions from above, otherwise fail
// i.e. if GenerateToken is called with a different instance of user, test will fail
.Verifiable("ContainsKey not called.");
// #### ACT ####
// Pass the token generator mock to our account service
var _accountService = new AccountService(_tokenGenerator.Object);
var register = await _accountService.Register(_applicationUser, "password");
var token = await _accountService.GenerateEmailConfirmationTokenAsync(userMock.Object.First());
// #### VERIFY ####
// Verify that GenerateToken method has been called with correct parameters
_tokenGenerator.Verify();
// verify that the GenerateEmailConfirmationTokenAsync returned the expected token abc123456
Assert.Equals(token, "abcd123456");
}
验证调用UserManager<T>.CreateAsync
的示例:
// #### SETUP ####
var _userManager = new Mock<UserManager<ApplicationUser>>()
.Setup(um => um.CreateAsync(It.Is(user))
.Verifiable("UserManager.CreateAsync wasn't called!");
var _accountService = new AccountService(_userManager);
// #### ACT ####
var register = await _accountService.Register(_applicationUser, "password");
// #### VERIFY ####
// Verify that GenerateToken method has been called with correct parameters
_userManager.Verify();
// verify that the GenerateEmailConfirmationTokenAsync returned the expected token abc123456
这确保你的AccountServce.CreateAsync
方法调用Identity。如果您稍后添加逻辑,这将确保在将来进行调用,或者如果您添加一些阻止CreateAsync
被调用的逻辑,测试将失败。这个测试测试行为。
编辑
如果您不知道mock是如何工作的,请注意:UserManager<T>.CreateAsync
的原始代码将永远不会执行。mock完全覆盖该方法(因此它只适用于具有virtual
方法的接口和类!!),并跳过它的整个逻辑,只返回一个预定义的值(在设置mock期间在.Returns(...)
方法中指定的值)。模型是用来返回假的/预先确定的值,所以你有确定的方法来测试一个类或功能。在集成测试中,mock的值低于单元测试,在单元测试中,您只想测试特定的代码片段(单元),而不需要外部依赖项,如数据库、文件系统或网络