Mock HostingEnvironment.QueueBackgroundWorkItem в тесте xunit

У меня есть метод, использующий HostingEnvironment.QueueBackgroundWorkItem, который я хочу unit test выполнить некоторое поведение перед этим вызовом, однако тест не работает с System.InvalidOperationException : Operation is not valid due to the current state of the object.

Я подозреваю, что мне нужно высмеять HostingEnvironment, но не знает, как это сделать.

Ответы

Ответ 1

Чтобы решить эту проблему, я определил интерфейс

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

В производственном коде я внедряю реализацию

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

В тестовом коде я внедряю реализацию

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

Я думаю, что это ОК, так как модульные тесты работают, а мои классы, которые ставят очередь фоновых задач, отключаются от HostingEnvironment.

Ответ 2

Я сделал это, чтобы все было просто:

/// <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());
        }
    }
}

Затем для запуска задания просто:

BackgroundTaskScheduler.QueueBackgroundWorkItem(ct =>
{
     // bla
});

Ответ 3

Немного аккуратно, чем вызов HostingEnvironment.QueueBackgroundWorkItem, независимо от того, существует ли ASP.NET AppDomain, а затем ловит InvalidOperationException:

public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
{
    if (HostingEnvironment.IsHosted)
    {
        HostingEnvironment.QueueBackgroundWorkItem(workItem);
    }
    else
    {
        workItem.Invoke(new CancellationToken());
    }
}