Пересмешивающие методы библиотеки IFlurl, использующие NSubstitute, выдают исключение нулевой ссылки - PullRequest
0 голосов
/ 30 ноября 2018

Я использую flurl и пытаюсь выполнить модульное тестирование кода ниже:

public class MyRestClient
{
    public async Task<T> Request<T>(IFlurlRequest flurlRequest)
    {
        try  
        {
            return await flurlRequest
                    .WithOAuthBearerToken("my-hardcoded-token")
                    .GetAsync()
                    .ReceiveJson<T>();  
        }
        catch(HttpFlurlException)
        {
            throw new MyCustomException();
        }
    }
}

Что я хочу проверить, так это то, что если flurlRequest выдает исключение типа HttpFlurlException тогда будет выбрасывать MyCustomException.Моя идея состоит в том, чтобы сделать flurlrequest и выдать исключение.Вот как я выложил свой тест:

var moq = Substitute.For<IFlurlRequest>();
// Problem is with line below:
moq.When(x => x.WithOAuthBearerToken("dummy")).Do(x => { throw new HttpFlurlException(); } );

var myClient = new MyRestClient();

Func<Task> call = async () => { await myClient.Request<object>(moq); };

// FluentAssertions
call.Should().Throw<MyCustomException>();

Код при запуске возвращает исключение NullReferenceException:

Exception has occurred: CLR/System.NullReferenceException
An exception of type 'System.NullReferenceException' occurred in 
Flurl.Http.dll but was not handled in user code: 'Object reference not 
set to an instance of an object.'
at Flurl.Http.HeaderExtensions.WithHeader[T](T clientOrRequest, String name, Object value)

Так что я вижу что-то связанное с заголовками ... поэтому я попробовал такжевысмеивая это, добавив:

var moq = Substitute.For<IFlurlRequest>();
moq.Headers.Returns(new Dictionary<string, object> { {"dummy", new {} };

Но я постоянно получаю одно и то же исключение.Что я делаю неправильно?

1 Ответ

0 голосов
/ 30 ноября 2018

WithOAuthBearerToken - это метод расширения, который означает, что он не может быть напрямую смоделирован NSubstitute.Когда вы вызываете When..Do или Returns для метода расширения, он запускает реальный код метода расширения.(Я рекомендую добавить NSubstitute.Analyzers в ваш тестовый проект для обнаружения этих случаев.)

Отслеживая реализацию метода расширения во время написания, должна быть возможность смоделировать Headers свойство бросать требуемое исключение, но я думаю, что это затягивает слишком много внутренних знаний о библиотеке и приведет к хрупким тестам, которые тесно связаны с этой конкретной реализацией (чего мы стремимся избежать с помощью насмешек!).

Я бы очень опасался издеваться над библиотекой третьей части, как я обрисовал в этот ответ :

Другой вариант заключается впроверить это на другом уровне.Я думаю, что трение в тестировании текущего кода состоит в том, что мы пытаемся заменить детали [сторонней библиотеки], а не интерфейсы, которые мы создали для разделения логических деталей нашего приложения.Ищите «не издевайтесь над типами, которые вам не принадлежат» для получения дополнительной информации о том, почему это может быть проблемой (я писал об этом раньше здесь ).

Если возможно, я предлагаю попробовать вместо этого использовать встроенную поддержку тестирования Flurl .Это должно позволить вам подделать нужное вам поведение, не требуя конкретных подробностей о внутренней реализации Flurl.

...