2017-02-21 58 views
1

我抓我的頭有點試圖找出如何測試像下面這樣: 這裏是GetProjects方法。如何在NUnit中傳遞UserId?

[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); 
     } 
    } 
} 

我試圖通過用戶id,但不知道從哪裏寫。

回答

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); 
     } 
    } 
} 
+1

這解決了我的問題。現在我不需要更改已經寫入的代碼。 –

1

它不是「mockable」,你應該創建一個不同的功能,將接收到的用戶名作爲參數。

您的WebAPI將調用該函數,並且您的測試將測試邏輯。

+0

對於這一點,我將不得不改變apicontroller的現有代碼?或者有另一種方法? –

+0

您需要更改apicontroller的現有代碼,從中提取邏輯。 –

1

靜態訪問會創建在測試期間不容易被忽略的硬依賴關係。

解決方法是將該依賴關係拉出待測方法。我會做這樣的事情,因此IUserProvider依賴可以在測試時被模擬,並提供適合測試的任何用戶標識。

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); 
     } 
    } 
} 

第一行中安排部分新創建的IUserProvider和設置GetUserId()一個模擬返回測試用戶ID。

+0

這是很好的方法。有一點仍不清楚。我將如何調用getUserId方法並使用該用戶ID在NUnit中獲取UserProjects?因爲我想爲不同的用戶測試GetProjects()。 –