【问题标题】:How to pass UserId in NUnit?如何在 NUnit 中传递 UserId?
【发布时间】:2017-07-11 05:07:49
【问题描述】:

我有点摸不着头脑,想弄清楚如何测试以下内容: 这里是 GetProjects 方法。

[Authorize]
[HttpGet]
[Route("api/UserProject/GetUserProjects")]
public HttpResponseMessage GetProjects()
{
    string userId = User.Identity.GetUserId();
    if (!ModelState.IsValid)
    {
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
    }

    try
    {
        List<ProjectDto> userProjectsDtos = projectBll.GetProjects(userId);
        return Request.CreateResponse(HttpStatusCode.OK, userProjectsDtos);
     }
     catch (Exception)
     {
        return new HttpResponseMessage(HttpStatusCode.InternalServerError);
     }
}

我正在尝试为该方法运行 NUnit 测试。

[TestClass]
public class TestUserProjects
{
    [TestMethod]
    public void GetUserProjectsTest()
    {
        // Arragnge
        var controller = new UserProjectController();
        controller.Request = new HttpRequestMessage();
        controller.Configuration = new HttpConfiguration();

        foreach (var testUserId in GetTestUserIds())
        {
            // Act
            var response = controller.GetProjects();

            // Assert
            List<ProjectDto> projects;
            Assert.IsTrue(response.TryGetContentValue<List<ProjectDto>>(out projects));
            //Assert.AreEqual(5, projects.Count); // Check projects count
            Assert.AreEqual(HttpStatusCode.OK,response.StatusCode);
            Assert.AreEqual(HttpStatusCode.OK, response.StatusCode,"GetUserProjects : id is {0} and count is {1}",testUserId,projects.Count);
            System.Diagnostics.Debug.WriteLine("GetUserProjects : for id {0} ProjectCount = {1}", testUserId, projects.Count);
        }
    }
}

我正在尝试传递 userId ,但不知道在哪里写。

【问题讨论】:

    标签: c# visual-studio unit-testing asp.net-web-api nunit


    【解决方案1】:

    如果请求是经过身份验证的,那么User 属性应该填充经过身份验证的用户的原则。然而,在单元测试期间,框架不会填充它。

    对于ApiController,您可以在安排单元测试时设置User 属性。但是,GetUserId() 扩展方法正在寻找 ClaimsIdentity,因此您应该提供一个

    [TestClass]
    public class TestUserProjects {
        [TestMethod]
        public void GetUserProjectsTest() {
            // Arrange
            var controller = new UserProjectController();
            controller.Request = new HttpRequestMessage();
            controller.Configuration = new HttpConfiguration();
    
            foreach (var testUserId in GetTestUserIds()) {
                //Arrange specific user
                var identity = new GenericIdentity(testUserId, "");
                identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, testUserId.ToString()));
                identity.AddClaim(new Claim(ClaimTypes.Name, testUserId.ToString()));
    
                var principal = new GenericPrincipal(identity, roles: new string[] { });
                var user = new ClaimsPrincipal(principal);
    
                controller.User = user;
    
                // Act
                var response = controller.GetProjects();
    
                // Assert
                List<ProjectDto> projects;
                Assert.IsTrue(response.TryGetContentValue<List<ProjectDto>>(out projects));
                //Assert.AreEqual(5, projects.Count); // Check projects count
                Assert.AreEqual(HttpStatusCode.OK,response.StatusCode);
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode,"GetUserProjects : id is {0} and count is {1}",testUserId,projects.Count);
                System.Diagnostics.Debug.WriteLine("GetUserProjects : for id {0} ProjectCount = {1}", testUserId, projects.Count);
            }
        }
    }
    

    【讨论】:

    • 这解决了我的问题。现在我不需要更改已经编写的代码。
    【解决方案2】:

    静态访问会创建在测试期间不容易被忽略的硬依赖。

    解决方案是将这种依赖关系从被测方法中提取出来。我会做类似的事情,以便在测试时可以模拟 IUserProvider 依赖项并提供适合测试的任何用户 ID。

    public interface IUserProvider
    {
        public string GetUserId();
    }
    
    public class UserProvider : IUserProvider
    {
        public string GetUserId()
        {
            return User.Identity.GetUserId();
        }
    }
    
    public class UserProjectController
    {
        private IUserProvider UserProvider { get; set;}
    
        public UserProjectController(IUserProvider userProvider)
        {
            UserProvider = userProvider;
        }
    
        [Authorize]
        [HttpGet]
        [Route("api/UserProject/GetUserProjects")]
        public HttpResponseMessage GetProjects()
        {
            string userId = UserProvider.GetUserId();
            if (!ModelState.IsValid)
            {
                return new HttpResponseMessage(HttpStatusCode.BadRequest);
            }
    
            try
            {
                List<ProjectDto> userProjectsDtos = projectBll.GetProjects(userId);
                return Request.CreateResponse(HttpStatusCode.OK, userProjectsDtos);
             }
             catch (Exception)
             {
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
             }
        }
    }
    

    测试时模拟 IUserProvider 的语法会随着不同的测试框架而改变。使用Moq 看起来像这样

    [TestClass]
    public class TestUserProjects
    {
        [TestMethod]
        public void GetUserProjectsTest()
        {
            // Arrange
            var userProviderMock = new Mock<IUserProvider>();
            userProviderMock.Setup(userProvider => userProvider.GetUserId())
                            .Returns("4e934c03-b02f-47bf-8bdf-e1c98a737cc6");
            var controller = new UserProjectController(userProviderMock.Object);
            controller.Request = new HttpRequestMessage();
            controller.Configuration = new HttpConfiguration();
    
            foreach (var testUserId in GetTestUserIds())
            {
                // Act
                var response = controller.GetProjects();
    
                // Assert
                List<ProjectDto> projects;
                Assert.IsTrue(response.TryGetContentValue<List<ProjectDto>>(out projects));
                //Assert.AreEqual(5, projects.Count); // Check projects count
                Assert.AreEqual(HttpStatusCode.OK,response.StatusCode);
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode,"GetUserProjects : id is {0} and count is {1}",testUserId,projects.Count);
                System.Diagnostics.Debug.WriteLine("GetUserProjects : for id {0} ProjectCount = {1}", testUserId, projects.Count);
            }
        }
    }
    

    安排部分中的第一行 new 创建一个模拟 IUserProvider 并设置 GetUserId() 以返回一个测试用户 ID。

    【讨论】:

    • 这是个好方法。有一件事还不清楚。我将如何调用 getUserId 方法并在 NUnit 中使用该 userId 获取 UserProjects ?因为我想为不同的用户测试 GetProjects()。
    【解决方案3】:

    它不是“可模拟的”,你应该创建一个不同的函数来接收用户名作为参数。

    您的 WebAPI 将调用该函数,您的测试将测试逻辑。

    【讨论】:

    • 为此,我是否必须更改 apicontroller 的现有代码?还是有别的办法?
    • 您将需要更改 apicontroller 的现有代码,从中提取逻辑。
    猜你喜欢
    • 1970-01-01
    • 2022-11-21
    • 2023-03-21
    • 1970-01-01
    • 2013-04-19
    • 2017-01-14
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多