Мок говорит 0 звонков, когда он перечисляет вызов? - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть модульный тест, который использует Moq для проверки интерфейсов и проверки вызовов. Вот тестовый код:

[Fact]
public void NewBlank_InvokesManagerAdd()
{
    // ReSharper disable once AssignNullToNotNullAttribute
    var newPath = Path.Combine(_testSaveDirectory, "InvokeBlank.txt");

    _dbManagerMock.Setup(manager => manager.KeynoteDBs).Returns(new ObservableCollection<KeynoteDBVM>());
    _dialogMock.Setup(dialog => dialog.GetSaveFileDialogResult(It.IsAny<SaveFileDialogData>()))
               .Returns(newPath);

    _commands.CmdNewBlank.Execute(null);

    _dbManagerMock
        .Verify(manager => manager.AddDB(It.IsAny<KeynoteDB>(), It.IsAny<int>()),
                Times.Once);
}

Однако, когда я запускаю это, я получаю этот тестовый сбой:

Moq.MockException

Expected invocation on the mock once, but was 0 times: manager => manager.AddDB(It.IsAny<KeynoteDB>(), It.IsAny<int>())

Performed invocations:

   Mock<IDBManager:1> (manager):

      IDBManager.KeynoteDBs
      IDBManager.IsLoading = True
      IDBManager.ActiveDB
      IDBManager.AddDB(KeynoteDB, -1)
      IDBManager.ActiveDB
      IDBManager.IsLoading = False

   at Moq.Mock.Verify(Mock mock, LambdaExpression expression, Times times, String failMessage)
   at Moq.Mock`1.Verify[TResult](Expression`1 expression, Func`1 times)
   at KMCore_Tests.AppCommandsTests.NewBlank_InvokesManagerAdd() in *my path*\AppCommandsTests.cs:line 140

Разве это не перечисляет этот вызов 1 раз в этом списке вызовов прямо в середина? Как это говорит, что у него 0 вызовов? Что мне не хватает? Я чувствую, что, должно быть, мне что-то не хватает, но я не вижу этого ...

EDIT

Хорошо, так что это оказалось проблемой состояния гонки, потому что команды асин c. Выполнение команды вызывает асинхронный метод c void, и он должен был нажать assert до того, как он достигнет фактического вызова (или, по крайней мере, это все, что я могу придумать). Я вставил ожидающий Task.Delay (500) после вызова execute и перед подтверждением, и он проходит сейчас.

Есть ли лучший способ проверить эту ситуацию? Команды, по сути, являются обработчиками кнопок, поэтому я думаю, что asyn c void здесь правильный из моего понимания, но это означает, что я не могу ждать его в модульном тесте ...

1 Ответ

1 голос
/ 21 апреля 2020

Вам следует избегать использования asyn c void в любом случае .

async void означает огонь и забыть. В вашем случае вы, похоже, этого не хотите, потому что вам нужно дождаться завершения метода asyn c.

Если вы не можете изменить сигнатуру метода, вы можете переместить тело async void method к Task возвращающему методу.

Так, например, измените

public async void MyAsyncVoidMethod()
{
    await Task.Delay(500);

    MethodToBeCalled();
}

на

// Wait this task in unit test
public Task MyAsyncTask { get; private set; }

public async void MyAsyncVoidMethod()
{
    MyAsyncTask = MyAsyncTaskMethod();
    await MyAsyncTask;
}

public async Task MyAsyncTaskMethod()
{
    await Task.Delay(500);

    MethodToBeCalled();
}

В качестве альтернативы, если какое-либо событие сработало после выполнения команды вы также можете подключиться к одному из этих событий, чтобы получать уведомления в своих тестах.

...