【问题标题】:unit testing in web api with N tier without actual database calls在没有实际数据库调用的情况下在具有 N 层的 Web api 中进行单元测试
【发布时间】:2020-07-31 11:37:40
【问题描述】:

我正在为我的 Web API 应用程序编写单元测试,使用 .net Core 创建。我使用 MSTest 和 MOQ 进行模拟。

它有很多层,如下所示。

Controller => Manager classes => Facade classes => Contract 类

我在控制器中提供了我模拟的实体。

[TestMethod]
public void InvoiceUpdateFinanceTest_Success()
{
    var mock = mockFactory.OutstandingInvoicesDetailsMock();

    dataController.InvoiceUpdateFinance(mock);
    Assert.IsTrue(true);
}

Contract Class正在创建数据库连接实例并进行数据库调用

合约层代码示例如下

public class GradeWiseSlab : IMaintainContract
{
  

    IDbConnection _db = new DBModel().InstanceCreation();
    
    DynamicParameters dp = new DynamicParameters();
    public MaintainContractEntities MaintainContractEntities { get; set; }
    public void SaveData()
    {
        dp.Add("@N_VENDOR_ID", MaintainContractEntities.VendorId);
        dp.Add("@N_CONTRACT_SUB_TYPE_ID", MaintainContractEntities.SubContractType);
        dp.Add("@N_PAYMENT_TERM", MaintainContractEntities.PaymentTerm);
        dp.Add("@S_TRANSACTION_CURRENCY", MaintainContractEntities.TransactionCurrency);
        dp.Add("@S_DOC_NAME", MaintainContractEntities.DocNames);
        dp.Add("@S_APPROVAL_STATUS", MaintainContractEntities.ApproalStatus);
        dp.Add("@D_FROM_DATE", MaintainContractEntities.FromDate);
        dp.Add("@D_TO_DATE", MaintainContractEntities.ToDate);
        this._db.Query(Constant.SP_GRADE_WISE_SLAB, dp, commandTimeout: 0, commandType: CommandType.StoredProcedure);
}

我如何编写覆盖所有层的测试用例,即从控制器到合约但没有实际的数据库可触及?

我没有使用实体框架,我使用的是 Dapper 库

【问题讨论】:

    标签: unit-testing asp.net-web-api mstest web-api-testing vs-unit-testing-framework


    【解决方案1】:

    如果您使用的是 EntityFramework,EF 现在有一个 InMemoryDatabase。

    但似乎并非如此。

    我必须重写你的一些“术语”,因为你没有显示很多代码并且术语有点混乱。

    Controller (WebApiLayer)=> Manager classes (BusinessLogic Layer) => DataLayer(这是对存储过程的调用实际存在的地方)。根据您的描述,我会说我的“DataLayer”是您的“Contract”层......恕我直言,“Contract”是一个令人困惑和模棱两可的名称......对于数据层来说不是一个好名字。但我离题了。

    通过上述设计,您可以将一些 IDataLayer 对象(例如,IEmployeeDataLayer)接口注入到您的经理(EmployeeManager:IEmployeeManager)中。您将拥有一个“真实的”具体的 EmployeeTheRealOneDataLayer 对象……并且您还可以模拟 IEmployeeDomainDataLayer .. 以便对您的 EmployeeManager 对象进行单元测试。

    我实际上在这里有一个“关闭”示例:

    https://github.com/granadacoder/dotnet-core-on-linux-one/blob/master/src/Bal/Managers/EmployeeManager.cs

    public class EmployeeManager : IEmployeeManager
    {
        private readonly ILogger<EmployeeManager> logger;
        private readonly IEmployeeDataLayer iedl;
    
        public EmployeeManager(ILoggerFactory loggerFactory, IEmployeeDataLayer iedl)
        {
            this.logger = loggerFactory.CreateLogger<EmployeeManager>();
            this.iedl = iedl;
        }
    

    使用我的单元测试代码,我将模拟 IEmployeeDataLayer ,以便能够测试 EmployeeManager 类。

    您的问题是..我如何在不访问真实数据库的情况下测试“真实”EmployeeDataLayer。

    这是我不认为它存在的突破点。数据层中的所有代码都被编码为(真的)访问数据库。

    这就是圣战的开始。有人会说“将它连接到 sqlexpress 数据库”......但是恕我直言,当这些不再成为单元测试(不仅仅在内存中运行)时......而是变得更具功能 测试。

    由于您没有使用 EF,因此您可能必须做出决定。对您的业务逻辑层编写单元测试“没问题”......并“跳过”DataLayer。事实上,我会将以下属性放在我的数据层类中。

    https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.excludefromcodecoverageattribute?view=netcore-3.1

    您的另一个选择是移动到更像这样的东西:(内存中的EF)

    https://docs.microsoft.com/en-us/ef/core/providers/in-memory/?tabs=dotnet-core-cli

    就个人而言,(实际上我在不使用 EF 时会这样做)(而且我也使用 Dapper,因为 Dapper 性能良好)......我跳过了 UNIT 测试数据层。 (强调“单元”测试)

    但是我们的 QA 会针对真实的数据库引擎(想想 SqlSExpress)编写 FUNCTIONAL 测试。这里需要注意的是,他们必须能够(我们每周选择一次)完全删除/刷新“qa 数据库”......并从种子数据中重建它。这可以防止人们编写功能测试......在表格上寻找硬编码的代理(主键)......但强制通过唯一约束来寻找项目。又名,它可以防止与 qa 功能测试数据库中的特定数据“过于结合”)。 (注意,这与 EF In Memory Database 的概念类似……因为当您使用 EF In Memory db 启动单元测试时,它在启动时基本上是“空的”)。

    PS

    您可以在此处查看更多面向 EF 的项目设置: https://github.com/granadacoder/oracle-ef-issues-demo/tree/master/src

    PPS

    我并不是说上面的想法是一个详尽的可能性列表。但是当其他想法开始越过“只是在记忆中”的界限时......这就是这些迷你圣战开始的时候。我对我们公司的“记忆中”线非常坚定。我们曾经有很多“MyProject.Tests.csproj”,这可以指单元测试或功能测试。现在我“强烈鼓励”将项目命名为“MyProject.UnitTests.csproj”或“MyProject.FunctionalTests.csproj”以消除歧义。不是每个人都喜欢我的“在沙滩上画线”的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-09
      • 2022-01-10
      • 2014-07-29
      • 1970-01-01
      • 1970-01-01
      • 2017-12-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多