我有ChangePassword
方法,我User.Identity.GetUserId()
找到UserId
。
问题:它总是返回null。不明白为什么。
我在另一篇文章中读到,GetUserById
使用以下代码行来查找Id
。我不知道如何模仿ClaimsTypes.NameIdentifier
。
返回ci.FindFirstValue(ClaimTypes.NameIdentifier);
ChangePassword方法(单位测试的方法)
public async Task<IHttpActionResult> ChangePassword(string NewPassword, string OldPassword)
{
_tstService = new TestService();
IdentityResult result = await _tstService.ChangePassword(User.Identity.GetUserId(), OldPassword, NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
单元测试
var mock = new Mock<MyController>();
mock.CallBase = true;
var obj = mock.Object;
obj.ControllerContext = new HttpControllerContext { Request = new HttpRequestMessage() };
obj.Request.SetOwinContext(CommonCodeHelper.mockOwinContext());
IPrincipal user = GetPrincipal();
obj.ControllerContext.RequestContext.Principal = user;
var result = await obj.ChangePassword(dto);
// GetPrincipal
public static IPrincipal GetPrincipal()
{
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
identity.Setup(x => x.Name).Returns("User1@Test.com");
identity.Setup(p => p.IsAuthenticated).Returns(true);
user.Setup(x => x.Identity).Returns(identity.Object);
Thread.CurrentPrincipal = user.Object;
return user.Object;
}
IOwinContext模拟代码
public static IOwinContext mockOwinContext()
{
var owinMock = new Mock<IOwinContext>();
owinMock.Setup(o => o.Authentication.User).Returns(new ClaimsPrincipal());
owinMock.Setup(o => o.Request).Returns(new Mock<OwinRequest>().Object);
owinMock.Setup(o => o.Response).Returns(new Mock<OwinResponse>().Object);
owinMock.Setup(o => o.Environment).Returns(new Dictionary<string, object> { { "key1", 123 } });
var traceMock = new Mock<TextWriter>();
owinMock.Setup(o => o.TraceOutput).Returns(traceMock.Object);
var userStoreMock = new Mock<IUserStore<IfsUser>>();
userStoreMock.Setup(s => s.FindByIdAsync("User1@ifstoolsuite.com")).ReturnsAsync(new IfsUser
{
Id = "User1@test.com",
FirstName = "Test",
LastName = "User1",
Email = "User1@test.com",
UserName = "User1@test.com",
});
var applicationUserManager = new IfsUserManager(userStoreMock.Object);
owinMock.Setup(o => o.Get<IfsUserManager>(It.IsAny<string>())).Returns(applicationUserManager);
return owinMock.Object;
}
答案 0 :(得分:6)
您的 GetPrincipal 可以更新为使用声明。
public static IPrincipal GetPrincipal() {
//use an actual identity fake
var username = "User1@Test.com";
var identity = new GenericIdentity(username, "");
//create claim and add it to indentity
var nameIdentifierClaim = new Claim(ClaimTypes.NameIdentifier, username);
identity.AddClaim(nameIdentifierClaim);
var user = new Mock<IPrincipal>();
user.Setup(x => x.Identity).Returns(identity);
Thread.CurrentPrincipal = user.Object;
return user.Object;
}
以下是一个示例,说明了上述方法的工作原理。
public partial class MiscUnitTests {
[TestClass]
public class IdentityTests : MiscUnitTests {
Mock<IPrincipal> mockPrincipal;
string username = "test@test.com";
[TestInitialize]
public override void Init() {
//Arrange
var identity = new GenericIdentity(username, "");
var nameIdentifierClaim = new Claim(ClaimTypes.NameIdentifier, username);
identity.AddClaim(nameIdentifierClaim);
mockPrincipal = new Mock<IPrincipal>();
mockPrincipal.Setup(x => x.Identity).Returns(identity);
mockPrincipal.Setup(x => x.IsInRole(It.IsAny<string>())).Returns(true);
}
[TestMethod]
public void Should_GetUserId_From_Identity() {
var principal = mockPrincipal.Object;
//Act
var result = principal.Identity.GetUserId();
//Asserts
Assert.AreEqual(username, result);
}
[TestMethod]
public void Identity_Should_Be_Authenticated() {
var principal = mockPrincipal.Object;
//Asserts
Assert.IsTrue(principal.Identity.IsAuthenticated);
}
}
}
您有一些设计问题。如果连接到实际实现,创建具体的TestService
将导致问题。这成为一个集成测试。摘要也表示依赖。
public interface ITestService {
Task<IdentityResult> ChangePassword(string userId, string oldPassword, string newPassword);
}
public abstract class MyController : ApiController {
private ITestService service;
protected MyController(ITestService service) {
this.service = service;
}
public async Task<IHttpActionResult> ChangePassword(string NewPassword, string OldPassword) {
IdentityResult result = await service.ChangePassword(User.Identity.GetUserId(), OldPassword, NewPassword);
if (!result.Succeeded) {
return GetErrorResult(result);
}
return Ok();
}
}
此外,您不应该模拟被测系统。你应该模拟SUT的依赖关系。根据您要测试的方法以及您在MyController
是抽象类的评论中指出的内容,应该应用以下测试
[TestClass]
public class MyControllerTests {
public class FakeController : MyController {
public FakeController(ITestService service) : base(service) { }
}
[TestMethod]
public void TestMyController() {
//Arrange
var mockService = new Mock<ITestService>();
mockService
.Setup(m => m.ChangePassword(....))
.ReturnsAsync(....);
var controller = new FakeController(mockService.Object);
//Set a fake request. If your controller creates responses you will need this
controller.Request = new HttpRequestMessage {
RequestUri = new Uri("http://localhost/api/my")
};
controller.Configuration = new HttpConfiguration();
controller.User = GetPrincipal();
//Act
var result = await controller.ChangePassword("NewPassword", "OldPassword");
//Assert
//...
}
}