c# - 如何测试将身份与只读属性一起使用的控制器?
问题描述
我有以下代码:
[Route("resources/avatar")]
[ApiController]
public class AvatarController : ControllerBase
{
private readonly ApplicationDbContext database;
private readonly IWebHostEnvironment environment;
private readonly IUserManagerWrapper userManagerWrapper;
public AvatarController(IUserManagerWrapper userManagerWrapper, IWebHostEnvironment environment,
ApplicationDbContext database)
{
this.userManagerWrapper = userManagerWrapper;
this.environment = environment;
this.database = database;
}
[HttpGet]
[Route("")]
public async Task<IActionResult> Index()
{
if (User == null) return DefaultImage();
var user = await this.userManagerWrapper.GetUserAsync(User);
if ((user?.Avatar?.Length ?? 0) == 0) return DefaultImage();
return File(user.Avatar, "image/jpeg");
}
}
我有一个测试这个问题Index Page
。
User
is a property
that 来自ControllerBase
并且是 type ClaimsPrincipal
。
我使用了一个wrapper
我会包装的地方usermanager
,然后使用interface
我会的一个mock
。
这种方法的问题是我无法将其设置ClaimsPrincipal
为,null
因为它是一个read-only
.
这是我的测试:
[TestFixture]
public class AvatarController_Should
{
[Test]
public async Task IndexReturnsDefaultImage()
{
var hostingEnvironmentMock = new Mock<IWebHostEnvironment>();
var dabataseName = nameof(IndexReturnsDefaultImage);
var options = AvatarTestUtil.GetOptions(dabataseName);
var userManagerWrapperMock = new Mock<IUserManagerWrapper>();
using (var actAndAssertContext = new ApplicationDbContext(options))
{
var sut = new AvatarController(userManagerWrapperMock.Object, hostingEnvironmentMock.Object, actAndAssertContext);
}
}
}
public class AvatarTestUtil
{
public static DbContextOptions<ApplicationDbContext> GetOptions(string databaseName)
{
var serviceCollection = new ServiceCollection()
.AddEntityFrameworkInMemoryDatabase()
.BuildServiceProvider();
return new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName)
.UseInternalServiceProvider(serviceCollection)
.Options;
}
}
}
我愿意使用全新的方法。
这就是我以前做测试的方式identity
,但我现在卡住了。
解决方案
查看 ControllerBase 的源代码,我们可以看到 User 是这样定义的
public ClaimsPrincipal User => HttpContext?.User;
所以User实际上来自HttpContext。但是 HttpContext 也是只读的。但是,深入挖掘源代码,我们可以看到 HttpContext 是从 ControllerContext 派生的
public HttpContext HttpContext => ControllerContext.HttpContext;
唉! ControllerContext 在具体实现中其实有一个setter!
public ControllerContext ControllerContext { get; set; }
如果需要,我们可以在这里设置一个全新的 ControllerContext。但我们真的只需要 ControllerContext.User。幸运的是,它也有一个二传手。由于您只需要设置 User,因此我们可以直接在此处进行设置,而无需新建另一个 ControllerContext。
using (var actAndAssertContext = new ApplicationDbContext(options))
{
var sut = new AvatarController(userManagerWrapperMock.Object, hostingEnvironmentMock.Object, actAndAssertContext);
sut.ControllerContext.HttpContext.User = null;
}
推荐阅读
- c# - 如何从 powershell 捕获错误并将它们写入 .txt 文件?
- javascript - 散景服务器:回调执行顺序
- jquery - 我的 Jquery 脚本不工作。单击(在移动设备上)时,栏(图标)不显示导航栏内容
- vuex - FormData 作为 vuex 操作的有效负载
- string - 如何使用地图中的键分配每个项目
- java - AspectJ : 查找找到的 JoinPoint 的源方法代码/名称
- ios - 尝试快速从数组中删除时,不应删除 tableview 单元格中的最后一个单元格
- kdb - 当使用多个参数调用时,扫描副词的行为如何?
- python-3.x - 从用户输入解析多行
- javascript - 刷新后如何保持选择菜单项