我正在尝试在.Net核心中专门针对身份进行一些模拟。 我创建了一个.Net核心类库项目,我相信我拥有所有正确的引用。我试图模拟的第一件事是Identity方法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'始终为null。如果我查看userMock,我也无法看到令牌。
答案 0 :(得分:1)
为了测试模拟,你首先需要将其设置为执行某些操作,否则它只是一个没有实现的空接口。
在您的具体情况下,您似乎根本不需要模拟。您创建ApplicationUser
用户的实例,从中创建一个DbSet模拟,然后从中取出第一个对象。这与将ApplicationUser
实例直接传递给您的服务相同。
相反,您正在将ApplicationUser
传递给模拟,它根本没有实现,因此您实际上根本不测试任何内容。
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
中的逻辑类型以及您在AccountService
中具有哪些依赖关系(如果您需要moq或不是moq)。
假设您有一个名为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
被调用的逻辑。此测试测试行为。
修改强>
如果您不知道模拟的工作方式,请注意:UserManager<T>.CreateAsync
的原始代码将从不执行。模拟完全覆盖了这个方法(因此它只适用于带有virtual
方法的接口和类!!)并跳过它的整个逻辑,只返回一个预定义的值(在安装过程中你在.Returns(...)
方法中指定的值模拟的)。
样机可以返回假/预定值,因此您可以通过确定的方式来测试类或功能。在集成测试中,模拟的值低于单元测试中的值,在单元测试中,您只想测试特定的代码片(单元),而不需要外部依赖,如数据库,文件系统或网络