Модульный тест - Макет - Проблема с переопределением - Метод расширения - PullRequest
0 голосов
/ 02 ноября 2019

Я пытаюсь написать модульный тест для следующего метода поиска Azure:

public async Task Write(ISearchIndexClient indexClient, Search search)
{
    await UploadContents(indexClient, search.SearchContents);
}

private static async Task UploadContents(ISearchIndexClient indexClient, IReadOnlyCollection<dynamic> searchContents) => await Task.Run(() => indexClient.Documents.Index(IndexBatch.Upload(searchContents)));

Код модульного теста 1:

public async Task Write_Success()
{
    var searchIndexClientMock = new Mock<ISearchIndexClient>();
    searchIndexClientMock
        .Setup(x => x.Documents.Index(It.IsAny<IndexBatch<Document>>(), It.IsAny<SearchRequestOptions>()))
        .Returns(It.IsAny<DocumentIndexResult>()).Callback(() => IndexBatch.Upload(It.IsAny<IEnumerable<Document>>()));

    var pushFunction = new SearchIndexWriter();

    Search search = new Search();

    await pushFunction.Write(searchIndexClientMock.Object, search);

    //Assert, Verify checks
}

Я получаюследующая ошибка:

Сообщение: System.NotSupportedException: неподдерживаемое выражение: ... => .... Index (It.IsAny> (), It.IsAny ()) Методы расширения (здесь:DocumentsOperationsExtensions.Index) нельзя использовать в выражениях настройки / проверки.

Код модульного теста 2:

public async Task Write_Success()
{
    var searchIndexClientMock = new Mock<ISearchIndexClient>();
    searchIndexClientMock
        .SetupGet(x => x.Documents).Returns(It.IsAny<IDocumentsOperations>());

    var pushFunction = new SearchIndexWriter();

    var search = new Search()
    {
        SearchContents = new List<dynamic>(),
    };

    await pushFunction.Write(searchIndexClientMock.Object, search);

    //Verify, Assert logic
}

Я получаю следующую ошибку:

Сообщение: System.NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта. в Microsoft.Azure.Search.DocumentsOperationsExtensions.IndexAsync [T] (операции IDocumentsOperations, пакет IndexBatch ^ 1, SearchRequestOptions searchRequestOptions, CancellationToken cancellationToken)в Microsoft.Azure.Search.DocumentsOperationsExtensions.Index [T] (операции IDocumentsOperations, пакет IndexBatch ^ 1, SearchRequestOptions searchRequestOptions)

Как проверить функциональность загрузки?

Ответы [ 2 ]

4 голосов
/ 02 ноября 2019

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

Я предлагаю абстрагировать эту стороннюю зависимость

private readonly ISearchService service;

//...assuming service injected
public SearchIndexWriter(ISearchService service) {
    this.service = service;
}

public Task Write(ISearchIndexClient indexClient, Search search) {
    return service.UploadContents(indexClient, search.SearchContents);
}

Старайтесь избегать тесной связи со статическими проблемами, поскольку это затрудняет модульное тестирование в изоляции.

Определение сервиса может выглядеть как

public interface ISearchService {
    Task UploadContents(ISearchIndexClient indexClient, IReadOnlyCollection<dynamic> searchContents);
}

с простой реализацией, котораяоборачивает внешнюю зависимость

public class SearchService : ISearchService  {
    private Task UploadContents(ISearchIndexClient indexClient, IReadOnlyCollection<dynamic> searchContents) 
        =>  indexClient.Documents.IndexAsync(IndexBatch.Upload(searchContents));
}

Хватит напрягаться при попытке протестировать код, который вы не можете контролировать. Вместо этого сосредоточьтесь на своей логике, которой вы можете управлять.

public async Task Write_Success() {
    //Arrange
    var serviceMock = new Mock<ISearchService>();
    serviceMock
        .Setup(_ => _.UploadContents(It.IsAny<ISearchIndexClient>(), It.IsAny<IReadOnlyCollection<It.AnyType>>())
        .ReturnsAsync(new object());

    var searchIndexClientMock = Mock.Of<ISearchIndexClient>();

    var pushFunction = new SearchIndexWriter(serviceMock.Object);

    Search search = new Search();

    //Act
    await pushFunction.Write(searchIndexClientMock.Object, search);

    //Assert, Verify checks
    //...
}
0 голосов
/ 02 ноября 2019

Согласно документации,

https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.search.idocumentsoperations?view=azure-dotnet

Существует только один метод Index и он имеет два параметра.

В методе UploadContent индексметод передается только один аргумент. Есть ли какая-то разница в версиях в этих двух проектах?

И ...

searchIndexClientMock
        .SetupGet(x => x.Documents).Returns(It.IsAny<IDocumentsOperations>());

В настройке возвращение должно быть конкретным экземпляром, а не It.IsAny<IDocumentsOperations>().

...