Как я могу использовать или смоделировать IWebJobsBuilder для проведения интеграционного теста моей функции Azure v2?

Для завершения в ES6 у нас есть классы (поддерживаемые на момент написания этого только в последних браузерах, но доступные в Babel, TypeScript и других транспилерах)

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();
1
задан Kzrystof 23 March 2019 в 16:16
поделиться

1 ответ

Я посмотрел код хоста функции Azure и нашел этот фрагмент кода в файле Program.cs:

var host = new HostBuilder()
                .SetAzureFunctionsEnvironment()
                .ConfigureLogging(b =>
                {
                    b.SetMinimumLevel(LogLevel.Information);
                    b.AddConsole();
                })
                .AddScriptHost(options, webJobsBuilder =>
                {
                    webJobsBuilder.AddAzureStorageCoreServices();
                })
                .UseConsoleLifetime()
                .Build();

Часть, которая меня заинтересовала, была AddScriptHost() метод расширения, который делает доступным экземпляр webJobsBuilder (реализацию IWebJobsBuilder).

Зная это, я создал следующий метод, который создает простой экземпляр IHost и использует мой существующий класс Startup, который содержит все внедренные сервисы:

/// <summary>
/// Builds an instance of the specified <typeparamref name="TFunctionType"/>
/// with the services defined in the <paramref name="startup"/> instance.
/// </summary>
/// <typeparam name="TFunctionType"></typeparam>
/// <param name="startup"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">
/// Thrown if:
/// - The <paramref name="startup" /> instance is not specified.
/// </exception>
public static TFunctionType Instanciate<TFunctionType>(Startup startup)
{
    Argument.ThrowIfIsNull(startup, nameof(startup));

    // --> Builds an IHost with all the services registered in the Startup.
    IHost host = new HostBuilder().ConfigureWebJobs(startup.Configure).Build();

    return Instanciate<TFunctionType>(host);
}

Метод Instanciate<TFunctionType> ищет конструктор TFunctionType и извлекает все сервисы из экземпляра IHost:

/// <summary>
/// Instanciates the specified <typeparamref name="TFunctionType"></typeparamref>.
/// </summary>
/// <typeparam name="TFunctionType"></typeparam>
/// <param name="host"></param>
/// <returns></returns>
private static TFunctionType Instanciate<TFunctionType>(IHost host)
{
    Type type = typeof(TFunctionType);

    // --> This part could be better...
    ConstructorInfo contructorInfo = type.GetConstructors().FirstOrDefault();

    ParameterInfo[] parametersInfo = contructorInfo.GetParameters();

    object[] parameters = LookupServiceInstances(host, parametersInfo);

    return (TFunctionType) Activator.CreateInstance(type, parameters);
}

/// <summary>
/// Gets all the parameters instances from the host's services.
/// </summary>
/// <param name="host"></param>
/// <param name="parametersInfo"></param>
/// <returns></returns>
private static object[] LookupServiceInstances(IHost host, IReadOnlyList<ParameterInfo> parametersInfo)
{
    return parametersInfo.Select(p => host.Services.GetService(p.ParameterType))
                         .ToArray();
}

Я поместил эти методы в класс HostHelper. Теперь в моем тесте я могу повторно использовать класс Startup.

Более того, я могу создать подкласс Startup, чтобы смоделировать фрагменты кода, которые используют какой-то ввод-вывод, чтобы сделать мои интеграционные тесты более устойчивыми:

public class CreateAccountFunctionTests
{
    private readonly CreateAccountFunction m_creationAccountFunction;

    public CreateAccountFunctionTests()
    {
        var startup = new Startup();

        m_creationAccountFunction = HostHelper.Instanciate<CreateAccountFunction>(startup);
    }

    [Fact]
    public void TestSomething()
    {
        // Arrange.
        HttpRequest httpRequest = /* builds an instance of HttpRequest */

        // Act.
        var result = m_creationAccountFunction.Run(httpRequest);

        // Assert.
        // Asserts the Status Code.
    }
}
0
ответ дан Kzrystof 23 March 2019 в 16:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: