我正在尝试对一个报表控制器进行单位测试,该报告控制器将userManager对象带到构造函数中。
public class ReportController : BaseReportController {
private readonly IUserService _userService;
public ReportController ( IOptions<AppSettings> appSettings,
UserManager<ApplicationUser> userManager,
IUserService userService ) : base( appSettings, userManager ) {
_userService = userService;
}
public async Task<ActionResult> Report ( string path ) {
var currentUser = await GetCurrentUserAsync();
var excludedItems = _userService.GetUserExcludedReportsById( currentUser.Id ).Select( er => er.Path );
if ( string.IsNullOrEmpty( path ) || excludedItems.Any( path.Contains ) ) {
return RedirectToAction( nameof(HomeController.Index), "Home" );
}
var customItems = _userService.GetUserCustomReportsById( currentUser.Id ).Select( er => er.Path );
if ( path.Contains( AppSettings.CustomReportsFolderName ) && !customItems.Any( path.Contains ) ) {
return RedirectToAction( nameof(HomeController.Index), "Home" );
}
var model = GetReportViewerModel( Request );
model.Parameters.Clear();
var dbname = _userService.GetDefaultDbName( (await GetCurrentUserAsync()).Id );
model.Parameters.Add( "connectionStr", new[] {
dbname
} );
//model.ReportPath = "/Portal Reports" + path;
model.ReportPath = path;
model.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Ntlm;
return View( "Report", model );
}
}
我认为我需要以某种方式为应用程序用户提供调用。因此,getCurrentUserAsync((将是第一个示例。这将传递到基础:
public virtual Task<ApplicationUser> GetCurrentUserAsync() {
return UserManager.GetUserAsync(HttpContext.User);
}
我已经创建了一个假人,但是它仍然在身份部分上错误,但异常。到目前为止,这是我的测试:
[Fact]
public void ReportControllerReturnsToIndexIfPathIsNull()
{
//Arrange
var context = new Mock<HttpContext>();
context.Setup(x => x.User).Returns(user.Object);
var mockUserService = new Mock<IUserService>();
AppSettings appSettings = new AppSettings() { };
IOptions<AppSettings> options = Options.Create(appSettings);
var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
var sut = new ReportController(options, new FakeUserManager(mockUserStore.Object), mockUserService.Object);
sut.HttpContext = context.Object;
//Act
var result = sut.Report("");
//Assert
}
}
public class FakeUserManager : UserManager<ApplicationUser>
{
public FakeUserManager(IUserStore<ApplicationUser> userStore)
: base(userStore/*new Mock<IUserStore<ApplicationUser>>().Object*/,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<ApplicationUser>>().Object,
new IUserValidator<ApplicationUser>[0],
new IPasswordValidator<ApplicationUser>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
{
}
public override Task<ApplicationUser> FindByIdAsync(string id)
{
return Task.FromResult(new ApplicationUser { Id = id });
}
}
我在这里的正确行吗?如何通过此httpcontext.user将其传递?非常感谢。
您不需要模拟GetUserAsync
,如果您不,实际上更好。您需要的只是模拟HttpContext
,以便返回正确的用户。
这是跳跃和的障碍,实际上提供了更好的测试。如果嘲笑GetUserAsync
,则您正在测试操作的特定实现,即使用GetUserAsync
获取用户的操作。如果您稍后决定直接从上下文中获得某些服务类别等。
同时,只要您基于HttpContext
查询当前用户,任何方法显然都会使用,因为那是"当前"用户的概念所处的概念,那么您就不会与任何一个实现联系在一起。只要动作以某种方式得到当前用户,它就可以。
update
var controller = new ReportController();
controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, "foo")
}));
}
};
,您可能需要在用户上设置的索赔方面进行一些操作,具体取决于您的代码正在做什么。以上是设置User.Identity.Name
的值,对于大多数目的而言,应该足够。标准索赔的完整列表在这里。