2014-06-11 15 views
5

Próbuję wyśmiać User.Identity w moim teście Api Controller.Unit Test Web Api 2 Mock User

To jest moja metoda API:

[Route(Urls.CustInfo.GetCustomerManagers)] 
    public HttpResponseMessage GetCustomerManagers([FromUri]int groupId = -1) 
    { 
     var user = User.Identity.Name; 
     if (IsStaff(user) && groupId == -1) 
     { 
      return ErrorMissingQueryStringParameter; 
     } 
     ... 
    } 

Poszedłem za sugestię w tym poście: Set User property for an ApiController in Unit Test ustawić właściwość użytkownika.

To moja próba:

[TestMethod] 
    public void User_Without_Group_Level_Access_Call_GetCustomerManagers_Should_Fail() 
    { 
     Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers"}); 
     var response = m_controller.GetCustomerManagers(); 

     Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); 
    } 

Ale gdy badanie przeprowadzane jest właściwość Użytkownik zawsze ma wartość null.

Próbowałem nawet przenieść linię do ustawienia CurrentPrincipal w metodę api tuż przed wywołaniem User.Identity, ale nadal jest pusta.

Co robię źle? Jeśli to podejście nie działa w przypadku interfejsu webowego 2, jaki jest najlepszy sposób na symulowanie/symulowanie właściwości użytkownika?

Dzięki!

Odpowiedz

13

Można ustawić użytkownikowi ControllerContext.RequestContext.Principal:

controller.ControllerContext.RequestContext.Principal = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers"}); 

lub skrótowej równowartość:

controller.User = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers"}); 
+1

Po ustawieniu Principal w ten sposób, UserId nie jest ustawiony. Potrzebuję go ustawić, ponieważ logika w moim testowanym systemie opiera się na identyfikatorze użytkownika. Na przykład. 'User.Identity.Name' jest wypełnione (" Bob "), ale nie' User.Identity.GetUserId() '. – Bart

+0

@Bart kiedykolwiek rozwiązałeś to? –

+0

@Ben Hall Minęło trochę czasu, ale nie sądzę, żebym to zrobił. Myślę, że moje obejście było po prostu zmienić logikę, aby użyć 'UserName' zamiast' UserId'. – Bart

4

Dla łatwiejszego testów jednostkowych Web API 2, można użyć MyTested.WebApi. Oto przykład z uwierzytelnionego użytkownika:

MyWebApi 
    .Controller<WebApiController>() 
    .WithAuthenticatedUser(user => user.WithUsername("NewUserName")) 
    .Calling(c => c.SomeAction()) 
    .ShouldReturn() 
    .Ok(); 
0

I udało się rozwiązać ten faktycznie ustawić coś, aby powrócić do GetUserId(), w przeciwieństwie do nazwy użytkownika danego odpowiedź z największą liczbą głosów. Przepraszam, że Oyu będzie musiał przetłumaczyć z mojego użycia FakeItEasy na narzędzie kpiące z twojego wyboru.

Claim claim = new Claim("", userId); 
ClaimsIdentity fakeClaimsIdentity = A.Fake<ClaimsIdentity>(); 
A.CallTo(() => fakeClaimsIdentity.FindFirst(A<string>.Ignored)).Returns(claim); 

IPrincipal fakeIPrincipal = A.Fake<IPrincipal>(); 
A.CallTo(() => fakeIPrincipal.Identity).Returns(fakeClaimsIdentity); 

var controller = new AuthorisedServicesController() 
{ 
     User = fakeIPrincipal 
}; 

Jednak lepszym rozwiązaniem (jeśli został ponownie pisania kodu) byłoby streszczenie rzeczywisty kod wywołujący GetUserId więc mogę następnie wstrzyknąć do obiektu, który może sprawić, że połączenie to jest łatwo mockable. Trochę jak fabryka.