0

I am using xUnit and trying to unit test my WebAPI controller below:

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

And my test is below:

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

The mocked call to the repository seems to work fine when I debug into the controller, however when the method returns my actionResult is null. Therefore the response is also null etc.

Now I have a similar controller and test and that works fine with the main difference being that the controller does not return an array of objects but a single collection (i.e. the accounts but not how many records were found).

When running this it works fine, so in my mind I am feeling that something is wrong with the mocking of the objects and how they are handled by the response when wrapped into an object array.

Am I doing something wrong here? Or is there an issue with FakeItEasy?

VasilisP
  • 136
  • 2
  • 11
  • 1
    That is because in the action you are returning an anonymous type (`new { ... }`) but in the test you cast the response as an object array (`object[]`). as an aside you should also enumerate the collection. – Nkosi Mar 24 '17 at 16:10
  • "my actionResult is null": are you sure? I think `response` is null, not `actionResult`, right? – Thomas Levesque Mar 24 '17 at 16:14
  • While I am not all that familiar with FakeItEasy, how is the dependency being injected into the class/method under test? – Nkosi Mar 24 '17 at 16:15
  • @Nkosi I see what you are saying but it fails on var actionResult = this.UsersSearchController.Post(this.UserSearchRequest); before we do the casting to the OkNegotiatedContentResult. Also the collection is being converted Enumerated inside the controller. My repository returns an IQueryable and then it casts is to an Enumerable. – VasilisP Mar 24 '17 at 16:24
  • @Nkosi The injection happens by using the [Fake] and [UnderTest] decorators, so the library knows what to fake. – VasilisP Mar 24 '17 at 16:27
  • @ThomasLevesque Sorry I had to enable the "Use the legacy C# and VB expression evaluators" option in debugging and you are right it is not the actionResult but my response conversion. – VasilisP Mar 24 '17 at 16:36

1 Answers1

3

Apparently your test expects the action result to be OkNegotiatedContentResult<object[]>, but it's actually returning a OkNegotiatedContentResult<(anonymous type)>.

Assuming your test is correct, your controller should return an array of objects, not an anonymous object. So you should change this line:

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

to this:

return this.Ok(new object[]{ users, numberOfRecords });
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Thanks. This seems to work, so it appears I was not viewing correctly the debug info so the error was on a different object. If I wanted to use an anonymous object would I have to use dynamics and a [assembly: InternalsVisibleTo("TestProject.TestClass")] attribute? Apart from the testability is there any other benefit of using the object type instead of an anonymous type from what gets returned from the controller? Keep in mind this is a WebAPI controller being called by an Angular service. – VasilisP Mar 24 '17 at 16:56
  • @VasilisP I don't think you could use an anonymous object. There's no way to share them across assembly. `InternalsVisibleTo` wouldn't help, because you would have no way to refer to the type, since, it has no name. – Thomas Levesque Mar 24 '17 at 17:00