2017-03-24 3 views
0

J'utilise xUnit et essayer de l'unité tester mon contrôleur de WebAPI ci-dessous:Test WebAPI 2 contrôleurs avec FakeItEasy ne fonctionne pas comme prévu

public IHttpActionResult Post(UserSearchRequest userSearchRequest) 
{ 
    int? numberOfRecords; 
    var users = this._userRepository.Search(userSearchRequest, out numberOfRecords).AsEnumerable(); 
    return this.Ok(new { users, numberOfRecords }); 
} 

Et mon test est ci-dessous:

[Fake] 
public User User { get; set; } 
[Fake] 
public UserSearchRequest UserSearchRequest { get; set; } 
[Fake] 
public IRepository<User> UserRepository { get; set; } 
[UnderTest] 
public UsersSearchController UsersSearchController { get; set; } 

public UsersSearchControllerTests() 
{ 
    Fake.InitializeFixture(this); 
} 

[Fact] 
public void Get_WithUserSearchRequest_ExpectCallToUserRepositoryAndCorrectResultsReturned() 
{ 
    int? numberOfRecords = 0; 
    var users = new[] { this.User }.AsQueryable(); 
    A.CallTo(() => this.UserRepository.Search(A<UserSearchRequest>.Ignored, out numberOfRecords)) 
     .Returns(users) 
     .AssignsOutAndRefParameters(users.Count()); 

    var actionResult = this.UsersSearchController.Post(this.UserSearchRequest); 
    var response = actionResult as OkNegotiatedContentResult<object[]>; 

    Assert.NotNull(response); 
    int? numberOfRecordsReturned = int.Parse(response.Content[1].ToString()); 
    Assert.Equal(users.Count(), numberOfRecordsReturned); 
} 

L'appel raillé au référentiel semble fonctionner correctement lorsque je débogue dans le contrôleur, mais lorsque la méthode renvoie mon actionResult est null. Maintenant, la réponse est également nulle.

Maintenant, j'ai un contrôleur et un test similaires et cela fonctionne très bien avec la différence principale étant que le contrôleur ne retourne pas un tableau d'objets mais une collection unique (c.-à-d. de nombreux enregistrements ont été trouvés). Lors de l'exécution cela fonctionne très bien, donc dans mon esprit, je pense que quelque chose ne va pas avec le moqueur des objets et comment ils sont gérés par la réponse lorsqu'ils sont enveloppés dans un tableau d'objets.

Est-ce que je fais quelque chose de mal ici? Ou y a-t-il un problème avec FakeItEasy?

+1

C'est parce que dans l'action que vous retournez un type anonyme ('nouveau {...}') mais dans le test cast la réponse comme un tableau d'objet ('object []'). En aparté, vous devriez également énumérer la collection. – Nkosi

+0

"mon actionResult est null": en êtes-vous sûr? Je pense que 'response' est nul, pas' actionResult', n'est-ce pas? –

+0

Même si je ne connais pas très bien FakeItEasy, comment la dépendance est-elle injectée dans la classe/méthode testée? – Nkosi

Répondre

3

Apparemment, votre test s'attend à ce que le résultat de l'action soit OkNegotiatedContentResult<object[]>, mais il renvoie en réalité un OkNegotiatedContentResult<(anonymous type)>.

En supposant que votre test est correct, votre contrôleur doit retourner un tableau d'objets, pas un objet anonyme. Donc, vous devez modifier cette ligne:

return this.Ok(new { users, numberOfRecords }); 

à ceci:

return this.Ok(new object[]{ users, numberOfRecords }); 
+0

Merci. Cela semble fonctionner, donc il semble que je ne visualisais pas correctement les informations de débogage donc l'erreur était sur un objet différent. Si je voulais utiliser un objet anonyme, devrais-je utiliser la dynamique et un attribut [assembly: InternalsVisibleTo ("TestProject.TestClass")]? En dehors de la testabilité existe-t-il un autre avantage d'utiliser le type d'objet au lieu d'un type anonyme à partir de ce qui est renvoyé par le contrôleur? Gardez à l'esprit qu'il s'agit d'un contrôleur WebAPI appelé par un service Angular. – VasilisP

+0

@VasilisP Je ne pense pas que vous pourriez utiliser un objet anonyme. Il n'y a aucun moyen de les partager à travers l'assemblage. 'InternalsVisibleTo' n'aiderait pas, car vous n'auriez aucun moyen de vous référer au type, puisqu'il n'a pas de nom. –