Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock HostingEnvironment.QueueBackgroundWorkItem in xunit test

I have a method using HostingEnvironment.QueueBackgroundWorkItem which I wish to unit test some behaviour before this call, however, the test is failing with System.InvalidOperationException : Operation is not valid due to the current state of the object.

I suspect this I need to mock the HostingEnvironment but unaware of how to.

like image 935
PMC Avatar asked Feb 11 '15 14:02

PMC


3 Answers

To resolve this issue I defined an interface

public interface ITaskScheduler
{
    void QueueBackgroundWorkItem(Action<CancellationToken> workItem);
}

In production code I inject implementation

public class AspNetTaskScheduler : ITaskScheduler
{
    public void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
    {            
        HostingEnvironment.QueueBackgroundWorkItem(workItem);
    }
}

In test code I inject implementation

public class TaskScheduler : ITaskScheduler
{
    public void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
    {
        workItem.Invoke(new CancellationToken());
    }
}

I think this is an OK solution since unit tests work and my classes that queue background tasks are decoupled from HostingEnvironment.

like image 191
Robertas Avatar answered Nov 17 '22 23:11

Robertas


I ended up doing this to keep things simple:

/// <summary>
/// add some jobs to the background queue
/// </summary>
public static class BackgroundTaskScheduler
{
    /// <summary>
    /// send the work item to the background queue
    /// </summary>
    /// <param name="workItem">work item to enqueue</param>
    public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
    {
        try
        {
            HostingEnvironment.QueueBackgroundWorkItem(workItem);
        }
        catch (InvalidOperationException)
        {
            workItem.Invoke(new CancellationToken());
        }
    }
}

Then to fire a job simply:

BackgroundTaskScheduler.QueueBackgroundWorkItem(ct =>
{
     // bla
});
like image 39
artfulhacker Avatar answered Nov 18 '22 00:11

artfulhacker


A little bit neater than calling HostingEnvironment.QueueBackgroundWorkItem regardless of whether there's an ASP.NET AppDomain then catching the InvalidOperationException is:

public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
{
    if (HostingEnvironment.IsHosted)
    {
        HostingEnvironment.QueueBackgroundWorkItem(workItem);
    }
    else
    {
        workItem.Invoke(new CancellationToken());
    }
}
like image 7
Stephen Aggett Avatar answered Nov 18 '22 00:11

Stephen Aggett