我正在使用 ASP.NET Web API 的单元测试编写测试用例。
现在我有一个动作,该动作调用我在服务层中定义的某个方法,在那里我使用了以下代码行。
string username = User.Identity.Name;
// do something with username
// return something
现在我该如何为此创建单元测试方法,我遇到了空引用异常。我对编写单元测试和其他相关内容还比较新。
我想仅使用单元测试来解决这个问题。请帮我一下。
我正在使用 ASP.NET Web API 的单元测试编写测试用例。
现在我有一个动作,该动作调用我在服务层中定义的某个方法,在那里我使用了以下代码行。
string username = User.Identity.Name;
// do something with username
// return something
现在我该如何为此创建单元测试方法,我遇到了空引用异常。我对编写单元测试和其他相关内容还比较新。
我想仅使用单元测试来解决这个问题。请帮我一下。
以下方法仅是其中一种:
public class FooController : ApiController {
public string Get() {
return User.Identity.Name;
}
}
public class FooTest {
[Fact]
public void Foo() {
var identity = new GenericIdentity("tugberk");
Thread.CurrentPrincipal = new GenericPrincipal(identity, null);
var controller = new FooController();
Assert.Equal(controller.Get(), identity.Name);
}
}
这是在NerdDinner
测试教程中我发现的另一种方法。它在我的情况下起作用:
DinnersController CreateDinnersControllerAs(string userName)
{
var mock = new Mock<ControllerContext>();
mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
var controller = CreateDinnersController();
controller.ControllerContext = mock.Object;
return controller;
}
[TestMethod]
public void EditAction_Should_Return_EditView_When_ValidOwner()
{
// Arrange
var controller = CreateDinnersControllerAs("SomeUser");
// Act
var result = controller.Edit(1) as ViewResult;
// Assert
Assert.IsInstanceOfType(result.ViewData.Model, typeof(DinnerFormViewModel));
}
请确保您阅读了完整的章节:模拟 User.Identity.Name 属性
该章节使用了 Moq
模拟框架,您可以通过 NuGet 在您的 测试项目
中安装它:http://nuget.org/packages/moq
使用WebApi 5.0略有不同。现在你可以这样做:
controller.User = new ClaimsPrincipal(
new GenericPrincipal(new GenericIdentity("user"), null));
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "Nikita"),
new Claim(ClaimTypes.NameIdentifier, "1")
};
var identity = new ClaimsIdentity(claims);
IPrincipal user = new ClaimsPrincipal(identity);
controller.User = user;
对我来说,这些都没有起作用,我使用了另一个问题上的解决方案,该方案使用Moq在ControllerContext中设置用户名: https://dev59.com/yXM_5IYBdhLWcg3waSX9#6752924
GenericIdentity
和GenericPrincipal
,并设置Thread.CurrentPrincipal
。GenericPrincipal principal = new GenericPrincipal(new
GenericIdentity("UserName"),null); Thread.CurrentPrincipal = principal;
然后继承那个类...这样每个单元测试类都会有原则对象集
[TestClass]
public class BaseUnitTest
{
public BaseUnitTest()
{
GenericPrincipal principal = new GenericPrincipal(new GenericIdentity("UserName"),null);
Thread.CurrentPrincipal = principal;
}
}
[TestClass]
public class AdminUnitTest : BaseUnitTest
{
[TestMethod]
public void Admin_Application_GetAppliction()
{
}
}
在这里,我找到了另一种方法来为控制器级别的测试从测试方法中设置用户身份名称的解决方案。
public static void SetUserIdentityName(string userId)
{
IPrincipal principal = null;
principal = new GenericPrincipal(new GenericIdentity(userId),
new string[0]);
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
当我运行单元测试时 - 在我的情况下,它使用Windows身份验证和Identity.Name是我的域名,我还想在测试中更改它。 所以我使用 IAuthenticationFilter中希望使用的“黑客”方法
someController.ControllerContext.HttpContext = new DefaultHttpContext
{
User = new GenericPrincipal(new GenericIdentity(userName) , new []{string.Empty})
};
[Test]
public async Task GetAll_WhenUserNotExist_ReturnsNotFound()
{
// arrange
var autoMock = AutoMock.GetLoose();
const string userName = "harry@potter.com";
var customersServiceMock = autoMock.Mock<ICustomerService>();
customersServiceMock
.Setup(service => service.GetAll(userName)).Throws<UserDoesNotExistException>();
var customerController = autoMock.Create<CustomerController>();
//
// Create a new DefaultHttpContext and assign a generic identity which you can give a user name
customerController.ControllerContext.HttpContext = new DefaultHttpContext
{
User = new GenericPrincipal(new GenericIdentity(userName) , new []{string.Empty})
};
var httpResult = await customerController.GetAllCustomers() as NotFoundResult;
// act
Assert.IsNotNull(httpResult);
}
[HttpGet]
[Route("all")]
public async Task<IActionResult> GetAllCustomers()
{
// User identity name will return harry@potter now.
var userName = User.Identity?.Name;
try
{
var customers = await _customerService.GetAll(userName).ConfigureAwait(false);
return Ok(customers);
}
catch (UserDoesNotExistException)
{
Log.Warn($"User {userName} does not exist");
return NotFound();
}
}