我正在使用ASP.NET Web API的单元测试编写测试用例。现在我有了一个动作,它调用了我在服务层中定义的某个方法,我在其中使用了以下代码行。
string username = User.Identity.Name;// do something with username// return something
string username = User.Identity.Name;
// do something with username
// return something
现在我如何创建单元测试方法,我得到空引用异常。我对编写单元测试之类的东西还比较陌生。我只想使用单元测试来实现这一点。请帮我这个忙。
a0x5cqrl1#
下面的一个只是这样做的一种方式:
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); }}
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);
xpszyzbs2#
下面是我在NerdDinner测试教程中发现的另一种方法。它在我的情况下工作:
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));}
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));
请确保您阅读完整部分:Mocking the User.Identity.Name property它使用Moq mocking框架,您可以使用NuGet安装在Test project中:http://nuget.org/packages/moq
Moq
Test project
tjvv9vkg3#
在WebApi 5.0中,这一点略有不同。您现在可以:
controller.User = new ClaimsPrincipal( new GenericPrincipal(new GenericIdentity("user"), null));
controller.User = new ClaimsPrincipal(
new GenericPrincipal(new GenericIdentity("user"), null));
vxbzzdmp4#
这些都没有对我起作用,我在另一个问题上使用了这个解决方案,它使用Moq在ControllerContext中设置用户名:https://stackoverflow.com/a/6752924/347455
uyto3xhc5#
这是我的解决方案。
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;
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;
ru9i0ody6#
在这里我找到了另一种方法的解决方案,即如何从测试方法中为控制器级别的测试设置用户标识名。
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; } }
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;
r55awzrz7#
当我运行单元测试时-在我的情况下,它使用Windows身份验证和Identity。Name是我的域名,我也想为测试更改。所以我用such approach with 'hacking' things I want in IAuthenticationFilter
dl5txlt98#
如果你有很多控制器要测试,那么我建议你创建一个基类,在构造函数中创建一个GenericIdentity和GenericPrincipal,并设置Thread.CurrentPrincipal。
GenericIdentity
GenericPrincipal
Thread.CurrentPrincipal
GenericPrincipal principal = new GenericPrincipal(new GenericIdentity("UserName"),null); Thread.CurrentPrincipal = principal;
GenericPrincipal principal = new GenericPrincipal(new
GenericIdentity("UserName"),null); Thread.CurrentPrincipal = principal;
继承这个类。这样,每个单元测试类都将具有Principle对象集
[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() { }}
[TestClass]
public class BaseUnitTest
public BaseUnitTest()
GenericPrincipal principal = new GenericPrincipal(new GenericIdentity("UserName"),null);
public class AdminUnitTest : BaseUnitTest
public void Admin_Application_GetAppliction()
50few1ms9#
不知道AspNetCore是否改变了很多,但现在在Net7中,你可以简单地做到这一点
someController.ControllerContext.HttpContext = new DefaultHttpContext{ User = new GenericPrincipal(new GenericIdentity(userName) , new []{string.Empty})};
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 = "[email protected]"; 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);}
[Test]
public async Task GetAll_WhenUserNotExist_ReturnsNotFound()
// arrange
var autoMock = AutoMock.GetLoose();
const string userName = "[email protected]";
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
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(); } }
[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();
9条答案
按热度按时间a0x5cqrl1#
下面的一个只是这样做的一种方式:
xpszyzbs2#
下面是我在
NerdDinner
测试教程中发现的另一种方法。它在我的情况下工作:请确保您阅读完整部分:Mocking the User.Identity.Name property
它使用
Moq
mocking框架,您可以使用NuGet安装在Test project
中:http://nuget.org/packages/moqtjvv9vkg3#
在WebApi 5.0中,这一点略有不同。您现在可以:
vxbzzdmp4#
这些都没有对我起作用,我在另一个问题上使用了这个解决方案,它使用Moq在ControllerContext中设置用户名:https://stackoverflow.com/a/6752924/347455
uyto3xhc5#
这是我的解决方案。
ru9i0ody6#
在这里我找到了另一种方法的解决方案,即如何从测试方法中为控制器级别的测试设置用户标识名。
r55awzrz7#
当我运行单元测试时-在我的情况下,它使用Windows身份验证和Identity。Name是我的域名,我也想为测试更改。所以我用such approach with 'hacking' things I want in IAuthenticationFilter
dl5txlt98#
如果你有很多控制器要测试,那么我建议你创建一个基类,在构造函数中创建一个
GenericIdentity
和GenericPrincipal
,并设置Thread.CurrentPrincipal
。继承这个类。这样,每个单元测试类都将具有Principle对象集
50few1ms9#
不知道AspNetCore是否改变了很多,但现在在Net7中,你可以简单地做到这一点
一个工作单元测试的例子
控制器的实现