2

技术栈

  1. 用于数据库升级的 DBUP
  2. 适用于活动的 Azure 耐用型
  3. Rhino 模拟单元测试。

情况

目前,我已将我的数据库升级 (DBUp) 语句放在 HTTPStart 方法中,作为我的持久 azure 函数的入口点。

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

问题

这种方法的问题是 DBUp 使用静态类来升级 DB,我不能使用 Rhino 来模拟静态类上的方法。

问题

我想将 DBUp 部分包装在一个非静态类中,但是我需要模拟构造函数初始化。不确定这是否可行

代码 - 升级数据库的助手类

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;
        }
    }

代码 - 调用 Helper 类的 HTTPStart 方法

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;
       }

在此处输入图像描述

请参阅突出显示的区域。我想模拟构造函数初始化,以便在单元测试时不会发生 DB 调用。

任何人都可以帮忙,拜托。

问候塔伦

4

1 回答 1

3

使用抽象来避免与实现问题的紧密耦合。

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
    //...
}
于 2018-09-04T02:09:35.747 回答