Fel*_*lix 73 c# unit-testing xunit.net asp.net-core-mvc
我有一个ASP.NET MVC核心应用程序,我正在编写单元测试.其中一个操作方法使用用户名来实现某些功能:
SettingsViewModel svm = _context.MySettings(User.Identity.Name);
Run Code Online (Sandbox Code Playgroud)
这显然在单元测试中失败了.我环顾四周,所有建议都是从.NET 4.5到模拟HttpContext.我相信有更好的方法可以做到这一点.我试图注入IPrincipal,但它引发了一个错误; 我甚至试过这个(出于绝望,我想):
public IActionResult Index(IPrincipal principal = null) {
IPrincipal user = principal ?? User;
SettingsViewModel svm = _context.MySettings(user.Identity.Name);
return View(svm);
}
Run Code Online (Sandbox Code Playgroud)
但这也引发了一个错误.无法在文档中找到任何内容......
pok*_*oke 137
通过控制器User
访问HttpContext
控制器.后者存储在ControllerContext
.
替换用户的最简单方法是为构造用户分配不同的HttpContext.我们可以DefaultHttpContext
为此目的使用,这样你就不必模拟一切:
var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, "example name"),
new Claim(ClaimTypes.NameIdentifier, "1"),
new Claim("custom-claim", "example claim value"),
}, "mock"));
var controller = new SomeController(dependencies…);
controller.ControllerContext = new ControllerContext()
{
HttpContext = new DefaultHttpContext() { User = user }
};
Run Code Online (Sandbox Code Playgroud)
Nko*_*osi 15
在以前的版本中,您可以User
直接在控制器上进行设置,这可以进行一些非常简单的单元测试.
如果您查看ControllerBase的源代码,您会注意到它User
是从中提取的HttpContext
.
/// <summary>
/// Gets or sets the <see cref="ClaimsPrincipal"/> for user associated with the executing action.
/// </summary>
public ClaimsPrincipal User
{
get
{
return HttpContext?.User;
}
}
Run Code Online (Sandbox Code Playgroud)
并且控制器访问HttpContext
通道ControllerContext
/// <summary>
/// Gets the <see cref="Http.HttpContext"/> for the executing action.
/// </summary>
public HttpContext HttpContext
{
get
{
return ControllerContext.HttpContext;
}
}
Run Code Online (Sandbox Code Playgroud)
您会注意到这两个是只读属性.好消息是,ControllerContext
财产允许设定它的价值,这将是你的方式.
所以目标是获得该对象.在Core中HttpContext
是抽象的,因此模拟起来要容易得多.
假设有一个控制器
public class MyController : Controller {
IMyContext _context;
public MyController(IMyContext context) {
_context = context;
}
public IActionResult Index() {
SettingsViewModel svm = _context.MySettings(User.Identity.Name);
return View(svm);
}
//...other code removed for brevity
}
Run Code Online (Sandbox Code Playgroud)
使用Moq,测试看起来像这样
public void Given_User_Index_Should_Return_ViewResult_With_Model() {
//Arrange
var username = "FakeUserName";
var identity = new GenericIdentity(username, "");
var mockPrincipal = new Mock<IPrincipal>();
mockPrincipal.Setup(x => x.Identity).Returns(identity);
mockPrincipal.Setup(x => x.IsInRole(It.IsAny<string>())).Returns(true);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(m => m.User).Returns(mockPrincipal.Object);
var model = new SettingsViewModel() {
//...other code removed for brevity
};
var mockContext = new Mock<IMyContext>();
mockContext.Setup(m => m.MySettings(username)).Returns(model);
var controller = new MyController(mockContext.Object) {
ControllerContext = new ControllerContext {
HttpContext = mockHttpContext.Object
}
};
//Act
var viewResult = controller.Index() as ViewResult;
//Assert
Assert.IsNotNull(viewResult);
Assert.IsNotNull(viewResult.Model);
Assert.AreEqual(model, viewResult.Model);
}
Run Code Online (Sandbox Code Playgroud)
还可以使用现有的类,并仅在需要时进行模拟。
var user = new Mock<ClaimsPrincipal>();
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = user.Object
}
};
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
14134 次 |
最近记录: |