DBUp модульного тестирования (Rhino) в надежном методе HTTPStart запуска Azure - PullRequest
0 голосов
/ 04 сентября 2018

Технологический стек

  1. DBUP для обновления БД
  2. Azure Durable для занятий
  3. Rhino издевается над юнит-тестированием.

Положение

В настоящее время я поместил свои инструкции по обновлению БД (DBUp) в метод HTTPStart в качестве точки входа в мою надежную функцию лазури.

DeployChanges.To
.SqlDatabase(connectionString)
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
.LogToConsole()
.Build(); 

Задача

Проблема с этим подходом заключается в том, что DBUp использует статический класс для обновления БД, и я не могу использовать Rhino для макетирования методов в статическом классе.

Вопрос

Я думал об обёртывании части DBUp в нестатический класс, но тогда мне нужно было бы смоделировать инициализацию конструктора. Не уверен, что это сработает

Код - класс помощника, который обновляет DB

public class DBUPHelper
    {
        public bool UpgradeDB()
        {
            bool status = true;
            var connectionString = "Data Source=localhost;Initial Catalog=master;Integrated Security=True;Connect Timeout=15";
            var upgrader =
                DeployChanges.To
                    .SqlDatabase(connectionString)
                    .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
                    .LogToConsole()
                    .Build();

            var result = upgrader.PerformUpgrade();

            if (!result.Successful)
            {
                status = false;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(result.Error);
                Console.ResetColor();
            }
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Success!");
            Console.ResetColor();
            return status;
        }
    }

Код - HTTPStart Метод, который вызывает класс Helper

private static ILogger logObj;
           [FunctionName("HttpStart")]
           public static async Task<HttpResponseMessage> Run(
               [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
               [OrchestrationClient] DurableOrchestrationClientBase starter,
               string functionName,
               ILogger log, ExecutionContext context)
       {
           HttpResponseMessage response = null;            
           var config = new ConfigurationBuilder()
           .SetBasePath(context.FunctionAppDirectory)
           .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
           .AddEnvironmentVariables()
           .Build();
           Helper.Helper helper = new Helper.Helper(config.GetConnectionString("ConnString"););
           if (helper.UpgradeDB())
           {
               log.LogInformation("DB Upgraded Successfully");
               logObj = log;
               try
               {
                   var provider = new MultipartMemoryStreamProvider();
                   await req.Content.ReadAsMultipartAsync(provider);
                   Application policy = await GeneratePolicyObject(provider);
                   string instanceId = await starter.StartNewAsync(functionName, policy);
                   log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
                   response = starter.CreateCheckStatusResponse(req, instanceId);
                   response.Headers.RetryAfter = new RetryConditionHeaderValue(TimeSpan.FromSeconds(10));
               }
               catch (Exception ex)
               {
                   response = new HttpResponseMessage();
                   log.LogCritical(ex.ToString());
                   log.LogCritical(ex.InnerException.ToString());
                   log.LogCritical(ex.StackTrace);
                   response.Content = new StringContent(ex.ToString());
                   response.StatusCode = System.Net.HttpStatusCode.InternalServerError;
               }
           }
           else log.LogCritical("DB Upgrade Failed. Check logs for exception");
           return response;
       }

enter image description here

См выделенную область. Я хочу смоделировать инициализацию конструктора, чтобы вызовы БД не происходили во время модульного тестирования.

Может кто-нибудь помочь, пожалуйста.

С уважением, Тарун

1 Ответ

0 голосов
/ 04 сентября 2018

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

public interface IDBHelper {
    bool UpgradeDB();
}

public class DBUPHelper: IDBHelper {
    //...code omitted for brevity
}

Кроме того, поскольку тестируемый метод является статическим, выставьте статическое поле / свойство

public static class MyFunction {
    //At run time this will use default helper
    public static IDBHelper Helper = new DBUPHelper();

    private static ILogger logObj;
    [FunctionName("HttpStart")]
    public static async Task<HttpResponseMessage> Run(
        [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
        [OrchestrationClient] DurableOrchestrationClientBase starter,
        string functionName,
        ILogger log, ExecutionContext context)
    {
       HttpResponseMessage response = null;      
       if (helper.UpgradeDB()) {
           log.LogInformation("DB Upgraded Successfully");
           logObj = log;
           try
           {
               var provider = new MultipartMemoryStreamProvider();
               await req.Content.ReadAsMultipartAsync(provider);
               Application policy = await GeneratePolicyObject(provider);
               string instanceId = await starter.StartNewAsync(functionName, policy);
               log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
               response = starter.CreateCheckStatusResponse(req, instanceId);
               response.Headers.RetryAfter = new RetryConditionHeaderValue(TimeSpan.FromSeconds(10));
           }
           catch (Exception ex)
           {
               response = new HttpResponseMessage();
               log.LogCritical(ex.ToString());
               log.LogCritical(ex.InnerException.ToString());
               log.LogCritical(ex.StackTrace);
               response.Content = new StringContent(ex.ToString());
               response.StatusCode = System.Net.HttpStatusCode.InternalServerError;
           }
       }
       else log.LogCritical("DB Upgrade Failed. Check logs for exception");
       return response;
    }
}

, который можно заменить при изолированном тестировании

public async Task TestFunction {
    //Arrange
    var helper = MockRepository.GenerateMock<IDBHelper>();        
    MyFunction.helper = helper; //<<--override default helper with mock
    helper.Stub(_ => _.UpgradeDB()).Return(false);//or true is that is what you desire

    //...arrange other parameters / dependencies

    //Act
    var actual = await MyFunction.Run(...);

    //Assert
    //...
}
...