Day 24-Unit Test 应用於 ORM (以 Entity Framework 为例) (情境及应用-4)

Unit Test 应用於 ORM (以 Entity Framework 为例) - LINQ 介绍

今天的主题是要针对开发 .NET 应用程序最常遇到的资料库处理(参考文章:Easily Perform LINQ Mocking to Unit Test ASP.NET Core Application),而资料库处理手法有数种方式如原生 SQL、Entity Framework、Dapper 等手法;其中,我们以 Entity Framework 为本次的范例,再讨论 Entity Framework 之前,要先了解 C# 很常用的资料处理语法 —— LINQ。

LINQ 是一套可做为 .NET 开发环境中 C# 资料物件的查询、传递、转换的语法框架,也就是在 .NET 环境中可以用 SQL 的逻辑对资料进行处理;举例来说,若没有 LINQ 语法之前,假设现在有一组 C# 物件要取出符合条件的资料,程序码如下:

class Program
{
    static void Main()
    {
       List<string> classmates = new List<string> { "David", "Mary", "Mandy", "Kevin" };
       List<string> classmatesMStart = new List<string>();
      
       foreach (string classmate in classmates)
       {
         if (classmate[0].Equals("M"))
         {
           classmatesMStart.Add(classmate);
         }
       }
       
       foreach (string classmate in classmates)
       {
         Console.WriteLine(classmate);
       }
    }
}

但如果今天是用 LINQ 语法,则程序码如下:

class Program
{
    static void Main()
    {
       List<string> classmates = new List<string> { "David", "Mary", "Mandy", "Kevin" };
       List<string> classmateMStart = classmates.Where(c => c[0].Equals("M")).ToList();
      
       foreach (string classmate in classmates)
       {
         Console.WriteLine(classmate);
       }
    }
}

所以实务上还满常使用 LINQ,那接下来概述 Entity Framework 的功能。


Unit Test 应用於 ORM (以 Entity Framework 为例) - Entity Framework 介绍

Entity Framework 是应用於 .NET 与 SQL 之间沟通的桥梁,采用 (ORM, Object Relational Mapping) 技术,使用 Entity Framework 的好处是像资料库连线、关闭等等都已经处理好,只需专注在商业逻辑的撰写上即可。其中,使用 Entity Framework 会自动产制类似如下的程序码,这部分主要是跟 SQL 资料表之间的联系;同时,也是我们单元测试主要的测试目标,若想了解更细的内容,可参考 Entity Framework Tutorial

public partial class ClassmateContext : DbContext
{
    public ClassmateContext()
    {
    }

    public ClassmateContext(DbContextOptions<ClassmateContext> options)
        : base(options)
    {
    }

    public virtual DbSet<Classmate> Classmates { get; set; }
    
    // ...
}

https://ithelp.ithome.com.tw/upload/images/20210924/20127378Sqx1fkifXA.png
图一、Entity Framework 框架图(图源:Entity Framework Tutorial)


Unit Test 应用於 ORM (以 Entity Framework 为例) - 用程序码说故事

因此,今天的主题就在於如何在使用 Entity Framework 的情境下,做测试时把 Entity Framework 相关的元件抽离并注入假物件,并且假物件需符合 LINQ 可使用的格式,那我们先来看商业逻辑的部分:

public class ClassmateClass {
    private ClassmateContext ct;
    
    public ClassmateClass(ClassmateContext inCt) {
        ct = inCt;
    }

    public int GetClassmateId(string classmateName)
    {
         int classmateId = 0;

         if (!string.IsNullOrEmpty(classmateName))
         {
           classmateId = ct.Classmates
                           .Where(d => d.Name.Equals(classmateName))
                           .Select(d => d.Id)
                           .FirstOrDefault();
         }

         return classmateId;
    }
}

在从商业逻辑中,我们可以看到 Id 主要是从 Context 中的 Classmate Dbset 取得相对应的资料;因此,接下来要做的事情就是把 ClassmateContext 抽换成虚设常式,程序码如下:

public class StubClassmateContext<T>
{
   public ClassmateContext GetClassmateContext()
   {
        var options = new DbContextOptionsBuilder<ClassmateContext>()
                       .UseInMemoryDatabase(Guid.NewGuid().ToString())
                       .Options;
                         
        var context = new ClassmateContext(options);

        context.Classmates.Add(new Classmate { Id = 100, Name = "Kevin" });
        context.SaveChanges();
        
        return context;
    }
}

因此,就可以透过建构函式把虚设常式注入,如下:

[Test]
public void DemoStubContextTest()
{
    // Arrange
    var stubCt = new StubClassmateContext<ClassmateContext>().GetClassmateContext();
    var classmateClass = new ClassmateClass(stubCt);
    
    // Act
    int classmateId = classmateClass.GetClassmateId("Kevin");

    // Assert
    Assert.AreEqual(100, classmateId);
}

这样就算是把 Entity Framework 连线至真实的资料库抽换成自己设定的假资料,虽然在建立 StubClassmateContext 时所建立的连线依旧有用 Entity Framework 的语法(换言之,已经并非达到百分百自己控制的测试码);但以能验证从 Entity Framework 取出来的资料所做的逻辑是否正确,还是有其效益。


<<:  Swift纯Code之旅 Day14. 「TableView(5) - 点击TableViewCell」

>>:  2.3 Design System - Design Token

Day 30:Google Map 结合口罩资料 & 铁人赛最後一天

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

MLOps在金融产业:关於ML系统监控的why, what, how

我们常常听到,在一个ML专案当中,会需要做各种的资料监控。这些资料监控包含哪些呢? 开发流程 在开发...

Day-3 Python Bool 整数 整数运算

接着针对资料型态为数字进行说明: Bool 资料型态为: True 与 False 使用 bool(...

Day24 - 在 Kamigo 使用 Kamiflex

LINE Developers:https://developers.line.biz/zh-ha...

自动化测试,让你上班拥有一杯咖啡的时间 | Day 24 - 学习 trigger 的用法

此系列文章会同步发文到个人部落格,有兴趣的读者可以前往观看喔。 今天要跟大家分享当网页上有子表时,...