代码之家  ›  专栏  ›  技术社区  ›  Tarun Bhatt

Azure持久httpstart方法中的单元测试(Rhino)dbup

  •  2
  • Tarun Bhatt  · 技术社区  · 6 年前

    技术堆栈

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

    情况

    目前,我已经将db upgrade(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;
           }
    

    enter image description here

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

    有人能帮忙吗?

    尊敬的塔伦

    1 回复  |  直到 6 年前
        1
  •  3
  •   Nkosi    6 年前

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

    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
        //...
    }
    
    推荐文章