Ahmad
Ahmad

Reputation: 13416

readonly object for unit testing is being disposed when using 'using'

I have an object that is used a bunch of times within the same unit test, and in other unit tests within the same class, that is defined as follows:

private readonly Task<HttpResponseMessage> successfulResponse = Task.FromResult(
            new HttpResponseMessage()
            {
                StatusCode = System.Net.HttpStatusCode.OK,
                Content = new StringContent(@"{""EntitySets"":[{""ResultSets"":[{""Results"":[{""Type"":""Message""}],""Total"":2}],""EntityType"":""Message""}]}")
            });

Then in each of my relevant unit tests, I'm doing something like this:

mockHttpClient.Setup(m => m.SendAsync(It.Is<HttpRequestMessage>(v =>
            v.RequestUri.Host.Equals("example.com")),
            It.IsAny<CancellationToken>())).Returns(successfulResponse);

... where mockHttpClient is a mocked HttpClient.

But when I'm unit testing, this sort of logic is executed in a lot of places inside the code being tested:

using (HttpResponseMessage response = await this.client.SendAsync(request, cancellationToken))
{
//...
}

... where this.client is mockHttpClient from above. As you can tell, Moq provides my pre-prepared successfulResponse object here to simulate a http response.

Problem is, when the very first execution of such a using statement is executed, it disposes successfulResponse when it gets out of the using block, and all following using blocks fail with the following exception:

Test method TestProbe_Success threw exception: 
    System.ObjectDisposedException: Cannot access a disposed object.
    Object name: 'System.Net.Http.StringContent'.

So my question is, how can I prevent the code being tested from disposing this object, which is used multiple times within the same unit test and in other unit tests ?

Upvotes: 0

Views: 1237

Answers (1)

Nkosi
Nkosi

Reputation: 247283

The issue is that you are using a shared resource in your tests, that, if disposed by one test, will cause unwanted effects in another.

Change it to a function

private readonly Func<Task<HttpResponseMessage>> successfulResponse = () => Task.FromResult(
        new HttpResponseMessage() {
            StatusCode = System.Net.HttpStatusCode.OK,
            Content = new StringContent(@"{""EntitySets"":[{""ResultSets"":[{""Results"":[{""Type"":""Message""}],""Total"":2}],""EntityType"":""Message""}]}")
        });

and have the setup use the delegate in its Returns

mockHttpClient
    .Setup(m => m.SendAsync(It.Is<HttpRequestMessage>(v => 
            v.RequestUri.Host.Equals("example.com")
        ),
        It.IsAny<CancellationToken>())
    )
    .Returns(() => successfulResponse());

That way each time a response is returned, a new instance is used.

Upvotes: 3

Related Questions