Подтвердить что ты не робот

Stubbing Задача возврата метода в async unit test

Скажем, у меня есть следующий класс и интерфейс, от которого он зависит:

public class MyController
{
    private IRepository _repository;
    public MyController(IRepository repository)
    {
        _repository = repository;
    }

    public async Task MethodUnderTest(int someId)
    {
        var o = await _repository.FindById(someId);
        // update o
        await _repository.Commit();
    }
}

public interface IRepository
{
    Task Commit();
}

Когда я unit test этот метод, я могу сделать следующее (используя xUnit и Rhino Mocks):

[Fact]
public async Task MyTest()
{
    IRepository repositoryStub = MockRepository.GenerateStub<IRepository>();

    MyController controller = new MyController(repositoryStub);

    await controller.MethodUnderTest(1);
}

Это не удается с помощью System.NullReferenceException: ссылка на объект не установлена ​​в экземпляр объекта.

Со следующим StackTrace:

UnitTest.MyController.<MethodUnderTest>d__0.MoveNext() in 
\UnitTest\Class1.cs:line 35
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at \UnitTest\Class1.cs:line 20

Правильно ли, что эта ошибка возникает из-за того, что Commit() возвращает null и statemachine, сгенерированные для вызовов async/wait MoveNext() на null?

Я могу это исправить, сделав что-то вроде:

repositoryStub.Expect(r => r.Commit()).Return(Task.FromResult<bool>(true);

Но это немного странно. Я могу использовать любой T для FromResult<T>, и тест будет запущен. Я не могу найти метод FromResult, который вернет не общий Task.

Имеет ли значение, что я использую для T? Или я должен исправить это по-другому?

4b9b3361

Ответ 1

Вам нужно что-то вернуть; async Task методы никогда не возвращаются null.

T не имеет значения. Вы можете объявить static readonly Task SuccessTask = Task.FromResult<object>(null); как вспомогательную константу, если хотите. У меня есть похожие константы в моей библиотеке AsyncEx.

Ответ 2

Если вы нацеливаете .NET Framework 4.6 или новее, вы можете теперь использовать .Returns(Task.CompletedTask), что немного короче.