Как выполнить модульное тестирование с помощью Moq хранилища ключей Azure - PullRequest
0 голосов
/ 15 апреля 2019

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

Я разрабатываю это с C # и Moq (Framework), чтобывыполните тестирование.

Интерфейс следующий:

public interface IKeyVaultConnection
{
    string GetKeyVaultValue(string variableName);
}
 public class KeyVaultConnection
    {
        public KeyVaultClient keyVaultClient;
        private string endpointKeyVault;

        public KeyVaultConnection(string keyVaultAddress = "DefaultEndpoint")
        {
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
            keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
            endpointKeyVault = $"https://{ keyVaultAddress }.vault.azure.net";
        }

        private async Task<string> AsyncGetSecretValue(string keyName)
        {
            var secret = await keyVaultClient.GetSecretAsync($"{endpointKeyVault}/secrets/{ keyName }")
                    .ConfigureAwait(false);

            return secret.Value;
        }

        public string GetKeyVaultValue(string variableName)
        {
            Task<string> task = Task.Run(async () => await AsyncGetSecretValue(variableName));
            task.Wait();
            return task.Result;
        }
}

 Mock<IKeyVaultConnection> mock = new Mock<IKeyVaultConnection>();
//----->>>>>>   Need to setup the endpoint
 mock.Setup(x => x.GetKeyVaultValue(It.IsAny<string>())).Returns(It.IsAny<string>());
 // mock.Verify(x => x.GetKeyVaultValue(It.IsAny<string>()), Times.Once());

Мне нужно подделать соединение с конечной точкой, чтобы получить то, что я звонюэта функция один раз, и я получаю ошибки, такие как:

"KeyVaultErrorException: Operation returned an invalid status code 'NotFound'"

за непредоставление конечной точки.

Если я раскомментирую последнюю строку (mock.Verify(x => x.GetKeyVaultValue(It.IsAny<string>()), Times.Once());), я получаю это:

"Expected invocation on the mock once, but was 0 times: 
 x => x.GetKeyVaultValue(It.IsAny<string>())"

1 Ответ

0 голосов
/ 15 апреля 2019

Если вы рассматриваете свой класс просто как скромную оболочку, так что другие классы могут зависеть от ISomethingThatReturnsValues, не зная о KeyVaultClient, тогда насмешка KeyVaultClient не нужна.Нам нужно только пойти так далеко.Нам не нужно тестировать базовые классы, от которых мы зависим.

Другими словами, нужно ли проверять, что

keyVaultClient.GetSecretAsync($"{endpointKeyVault}/secrets/{ keyName }")

... на самом деле вызывает конечную точку для получения секрета?Оно делает.Вот что делает KeyVaultClient.GetSecretAsync(string).Если тест не пройден, что мы можем сделать?Мы не можем исправить этот класс.Точно так же, если бы мы пошли по этому пути до его логического завершения, нам пришлось бы тестировать все виды вещей.Когда мы создаем List<string> и добавляем строку, действительно ли она добавляется?Мы не тестируем эти вещи, потому что они уже протестированы, поэтому разумно предположить, что они работают должным образом.

Хорошим тестом для этого будет интеграционный тест, который проверяет, что ваш класс выполняет то, что ожидал.Или, если от этого зависит другой класс, вы можете написать интеграционный тест для этого класса, который не будет выполнен, если вы не сможете извлечь что-либо из хранилища ключей.Но это не потребовало бы насмешек.

Частично для удобства работы с , а не модульным тестированием класса это сводит его к минимуму, так что он действительно ничего не делает, кроме вызова внутреннего класса.В этом случае вы можете свернуть ваш метод public и private в один метод public и, возможно, еще один, чтобы предоставить параметр async:

    public async Task<string> GetSecretValueAsync(string keyName)
    {
        return await keyVaultClient.GetSecretAsync($"{endpointKeyVault}/secrets/{ keyName }");
    }

    public string GetSecretValue(string keyName) => GetSecretValueAsync(keyName).Result;

Теперь это более очевидно: этот классна самом деле не делает ничего, что требует модульного тестирования.Его полезное назначение - адаптировать KeyVaultClient к вашему интерфейсу - IKeyVaultConnection, чтобы другие классы не зависели напрямую от KeyVaultClient.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...