十大靠谱网赌平台-十大赌博平台排行榜

十大靠谱网赌平台-十大赌博平台排行榜

开发SQL查询测试系统. 第2部分

表的内容

介绍

几年前, 我开发了一个数据层测试系统的原型, 将其实现到开发过程中, 并向两个团队解释了如何使用它. 这是一个内部教育门户项目,几乎瞄准了丹麦的整个市场. 在这篇文章中,我将对所有这些进行总结,并讨论关键的变化.

首先,让十大靠谱网赌平台重复一些要点,这样你就可以了解上下文了. 这个框架是基于内部代码基础结构和使用的技术开发的,以便自动化和简化复杂SQL查询的测试过程. 特别是, 它支持测试单个SQL查询,并为新客户端安装干净的数据库, 以及检测隐藏的兼容性问题, 从MySQL 5升级十大靠谱网赌平台器.1到MySQL 5.6、然后迁移到MariaDB.

最初, the system was used on a small project that just included two teams; 然而, 十大靠谱网赌平台需要将其扩展到15个团队的其他项目中. 除了, 这是一个项目中的一个模块,专注于MS测试框架, 这确实使问题复杂化了.

要了解更多关于系统结构及其工作原理的信息,请查阅 第1部分.

变化

后不久实现, 开发人员经常报告问题, 因为这个框架要么很难,要么完全不可能使用. 我总是认真对待这些问题,试图帮助他们学习他们从未接触过的工具. 在我的业余时间,我也修复bug和提供改进.

将包

下一个阶段是在另一个更大的代码规模的项目上实现十大靠谱网赌平台的工具, 更复杂的数据库结构, 更复杂的SQL查询, 以及更多的开发者. 十大靠谱网赌平台的第一个任务是使库适应不同的基本测试框架. 这个项目使用了NUnit,而这个库最初是为MS测试开发的.

因此,十大靠谱网赌平台必须将整个库拆分为多个构建:DataLayer测试s.核心,DataLayer测试s.MS测试Driver, DataLayer测试s.NUnitDriver,并将它们组装成单独的NuGet包. 整体, 十大靠谱网赌平台在没有任何重大问题的情况下完成了对另一个测试框架的迁移, 成功地拆分和调整代码.

在创建适配器时,最大的问题是确定当前的测试上下文,以正确地用类和测试方法中使用的元数据定义属性.

在MS测试框架中,十大靠谱网赌平台使用 和测试Context 属性,以便将依赖注入到类中, 而对于NUnit框架, 此信息仅可通过 和测试Context.CurrentContext 全局变量. 使用适配器模式, 十大靠谱网赌平台将它们组合成一个公共接口,并根据基测试类实现它们.

/ / BaseDataProvider测试s.cs
公共 摘要 class BaseDataProvider测试s 
{
    受保护的 I和测试ContextProvider 和测试ContextProvider { 得到; ; }

    私人 List GetUseTableAttributes()
    {
        Type = GetType();

        IList 属性 = type
            .GetCustomAttributes(真正的)
            .ToList ();

        if (!字符串.IsNullOrWhiteSpace (和测试ContextProvider?.Current和测试Context?.MethodName))
        {
            MethodInfo testMethod = type.GetMethod (和测试ContextProvider.Current和测试Context.MethodName);
            if (testMethod != )
            {
                属性.AddRange (testMethod.GetCustomAttributes(真正的));
            }
        }

        返回 属性;
    }
}
/ / BaseMS测试DataProvider测试s.cs
公共 摘要 class BaseMS测试DataProvider测试s : BaseDataProvider测试s, I和测试ContextProvider 
{
    受保护的 BaseMS测试DataProvider测试s()
    {
        和测试ContextProvider = ;
    }

    公共 I和测试Context Current和测试Context =>  Ms和测试ContextAdapter(和和测试Context);
}

公共 class Ms和测试ContextAdapter : I和测试Context
{
    私人 只读的 和和测试Context _testContext;

    公共 Ms和测试ContextAdapter(和和测试Context和和测试Context)
    {
        _testContext =和testContext;
    }

    公共 字符串 测试Title => _testContext.测试名称;

    公共 字符串 MethodName => _testContext.测试名称;
}
/ / BaseNUnitDataProvider测试s.cs
公共 摘要 class BaseNUnitDataProvider测试s : 核心.BaseDataProvider测试s
{
    受保护的 BaseNUnitDataProvider测试s()
    {
        和测试ContextProvider =  NUnit和测试ContextProvider ();
    }
}

公共 class NUnit和测试ContextAdapter : I和测试Context
{
    私人 只读的 和和测试Context _testContext;

    公共 NUnit和测试ContextAdapter(和和测试Context和和测试Context)
    {
        _testContext =和testContext;
    }

    公共 字符串 测试Title => _testContext.测试.名称;

    公共 字符串 MethodName => _testContext.测试.Method名称;
}

公共 class NUnit和测试ContextProvider : I和测试ContextProvider
{
    公共 I和测试Context Current和测试Context =>  NUnit和测试ContextAdapter(和和测试Context.CurrentContext);
}

This allowed us to minimize code duplication; as a result, 适配器包很小, 而核心框架逻辑仍然保留在基础包中. 这里最重要的事情是维护包的正确版本:因为十大靠谱网赌平台做了不兼容的更改, 十大靠谱网赌平台必须将版本号提高到2.0.

外部实体

用于生成测试实体的原始规则集包括 ForeignKeyRule 规则,该规则允许您创建相关实体. 该规则涵盖了开发人员在为各种查询和数据结构创建新测试时的需求. 然而,在某种程度上,这已经不够了.

为了测试下一个查询,十大靠谱网赌平台有下面的表的模式来填充:

用于测试的数据结构模式 图1:用于测试的数据结构模式

十大靠谱网赌平台的任务是为 Group实体PersonGroup实体 与此同时,与 Group实体 to Course实体 比是1比1 PersonGroup实体 to Group实体,多对一. 在这个开发阶段,十大靠谱网赌平台尝试了很多方法来使用库提供的工具来填充所需的数据. 然而, 十大靠谱网赌平台没有成功地迅速找到适合所有人的解决办法, so, 最初, 十大靠谱网赌平台只是手动填写测试数据. 过了一段时间,十大靠谱网赌平台有了创建新规则的想法,类似于 ForeignKeyRule,但恰恰相反,我称之为 InsideOutForeignKeyRule.

ForeignKeyRule, 另一个实体首先被注入到数据库中, 然后通过分配新生成的标识符来链接它. 在新规则中, 这完全是相反的:十大靠谱网赌平台首先注入主要实体, 然后连接并插入一个新的.

因此,有了这个新规则,十大靠谱网赌平台终于能够写出简洁的实体生成代码.

/ / InsideOutForeignKeyRule.cs
公共 class InsideOutForeignKeyRule<TSource实体, TTar得到实体, TValue> : Base实体Rule
    在哪里 TSource实体 : 实体, ()
    在哪里 TTar得到实体 : 实体, ()
{
    私人 只读的 PropertyInfo _sourcePropertyInfo;
    私人 只读的 PropertyInfo _tar得到PropertyInfo;

    公共 InsideOutForeignKeyRule(Expression> sourceProperty, Expression> tar得到Property)
    {
        _sourcePropertyInfo = sourceProperty.GetProperty ();
        _tar得到PropertyInfo = tar得到Property.GetProperty ();

        if (_sourcePropertyInfo = =  | | _tar得到PropertyInfo = = )
        {
              InvalidOperationException (“实体属性无效”);
        }

        Applied实体Types.Add (typeof(TSource实体));
    }

    公共 覆盖 无效 调用(实体RuleContext上下文)
    {
        object sourceValue = _sourcePropertyInfo.GetValue(上下文.Current实体);
        if (sourceValue !=  && !sourceValue.= (默认的(TValue)))
        {
            tar得到实体 = 上下文.DataFactory.Create实体(上下文.实体RuleSet、上下文.实体GroupProviders, );
            _tar得到PropertyInfo.SetValue (tar得到实体 sourceValue);
            上下文.DataProvider.插入(tar得到实体);
        }
    }
}

数据插入优化

最初, 当十大靠谱网赌平台开发这个框架时, 十大靠谱网赌平台假设十大靠谱网赌平台通常只使用一种数据类型, 因此,生成的对象的存储是一个简单的类型化列表, 在最后阶段哪个被发送到数据库. 所有填充和生成实体的规则都有一个简单的接口,只有一个方法, 调用(实体RuleContext上下文),它可以在插入到基之前对实体进行更改. 同时, 十大靠谱网赌平台添加了更复杂的规则, 如ForeignKeyRule, 这就产生了不同类型的新实体. 该规则生成一个新实体, 将其插入数据库, 并使用生成的新标识符填充父实体的字段. 下面的代码生成21个数据插入请求, 哪些会显著降低测试性能.

DataFactory
	//指定Book实体作为生成的主实体 
  .CreateBuilder()
	//指定User实体依赖项,默认为1:1 
  .UseForeignKeyRuleint>(book => book.AuthorId, user => user.Id)
  //填写必需的字段
  .UseRule ( UniqueSetterRule(user => user.用户名)
  .UseUniqueSetterRule(book => book.标题)
	//(1*)生成20个Book实体条目 
  .CreateMany (20)
	//将实体发送到数据库 
  .InsertAll ();
  • (1 *)如此, 十大靠谱网赌平台创建了20个Book实体条目并将它们注入到内存中, 一个一个地使用前面声明的规则. 这样,十大靠谱网赌平台叫 UseForeignKeyRule 规则,它不使用任何临时存储,立即将新实体发送到数据库. 结果,十大靠谱网赌平台得到了20个插入单个实体的请求,并且在调用之后 InsertAll () 十大靠谱网赌平台得到了插入这20个的最后第21个查询 Book实体 项目.

实体施工工作流程图2:实体构建器工作流

当我最初设计和开发测试系统时, 我知道这个问题, 但首先,我想对一个生产项目测试开发的解决方案, 得到反馈, 然后继续发展. 现在,我可以看到这个库工作得很好,并且没有引起任何关键问题, 我终于可以做优化和增强了.

在新版本中,我创建了一个通用存储,可以访问任何类型的实体. 然而,它的主要特性是创建和分组数据插入请求.

以前, 实体生成器框架使用直接数据库访问, 在开发延迟编写工具方面,哪些使重新编写生成器的过程变得复杂. 这就是我将所有必要的方法移到接口的原因, 有一个特殊的临时存储和一个类直接与数据库工作.

为了实现一个工具的懒惰插入相关实体, 我必须首先修改描述新数据生成规则的工具. 我认为 调用 方法过时,目前使用两个新方法: OnBeforeInsertOnAfterInsert,分别在实体插入数据库之前和之后被调用. 用户还可以订阅将实体插入数据库的事件,以便获得Auto Increment字段的更新值,或者根据二级键在数据库中插入具有显式限制的实体.

在大多数情况下, the generation rules remained unchanged in terms of logic; 然而, 考虑到新的架构,我不得不重新设计相关的实体生成规则. 让十大靠谱网赌平台看看它以前是如何工作的,现在又是如何工作的.

/ /之前实现
公共 覆盖 无效 调用(实体RuleContext上下文)
{
    常量 字符串 tar得到实体Key = “ForeignKeyRule.Tar得到实体”;

    object sourceValue = _sourcePropertyInfo.GetValue(上下文.Current实体);
    if (sourceValue = =  | | sourceValue.= (默认的(TValue)))
    {
        //试图从组中检索数据,如果没有数据,则创建数据
        tar得到实体 = GetDataFromGroup()
            上下文.Current实体Group, 
            tar得到实体Key,
            () => 上下文.DataFactory.Create实体(上下文.实体RuleSet、上下文.实体GroupProviders)
        );
                
        var 价值 = _tar得到PropertyInfo.GetValue (tar得到实体);
        _sourcePropertyInfo.SetValue(上下文.Current实体, 价值);
    }
}

/ /当前实现
公共 覆盖 无效 OnBeforeInsert(实体RuleContext上下文)
{
    常量 字符串 tar得到实体Key = “ForeignKeyRule.Tar得到实体”;

    object sourceValue = _sourcePropertyInfo.GetValue(上下文.Current实体);
    if (sourceValue = =  | | sourceValue.= (默认的(TValue)))
    {
        //试图从组中检索数据,如果没有数据,则创建数据
        tar得到实体 = GetDataFromGroup()
            上下文.Current实体Group, 
            tar得到实体Key,
            () => 上下文.DataFactory.BuildAndInsert实体(上下文.实体RuleSet、上下文.实体GroupProviders)
        );

        //订阅额外的实体插入,以更新原始值
        上下文.InsertionDataProvider.SubscribeOnAfterInsert(tar得到实体, () =>
            {
                var 价值 = _tar得到PropertyInfo.GetValue (tar得到实体);
                _sourcePropertyInfo.SetValue(上下文.Current实体, 价值);
            });
    }
}

重新设计测试实体生成器语法

以前, 最初的语法完全符合我的目的, 但是经过几年的测试,它变得过于繁琐和难以理解. 与我一起工作的其他开发者也证实了这一点. 具有讽刺意味的是, 我自己必须花很多时间来理解几个月前创建的测试的情况.

这让我别无选择,只能修改实体生成的内部逻辑,以使构建器简单和灵活. It took me a lot to come up with 和 agree on a 新 format; as a result, 然而, 我设法设计了一种方便和轻量级的语法,有助于随着时间的推移更好地理解测试代码.

我将在这里列出前面的语法问题, 这样你就能理解为什么我最终选择做出改变.

  1. 冗长的方法名可能会让开发人员感到困惑.
  2. 难以管理实体创建规则的可见性
  3. 不能同时使用多个实体

为了更好地理解这些问题的根本原因,让十大靠谱网赌平台以这段代码为例.

var 用户= DataFactory
    .CreateBuilder()
    //到目前为止一切都好
    .UseUniqueSetterRule(user => user.用户名)
    //试图为另一个(Book)实体添加规则
    // UseRule指的是什么?
    .UseRule ( UniqueSetterRule(book => book.标题))
    //更多实体类型操作 
    .UseInsideOutForeignKeyRuleint>(user => user.Id, book => book.AuthorId)
    // ... 在创建N个附加规则之后…
    //十大靠谱网赌平台创建的实体?
    .CreateMany (5)
    .InsertAll ();

如你所见, 问题在于所有的规则都是线性的, 它们没有以任何方式分组, 虽然声明主实体看起来很简单, 许多不必要的东西出现在所有的其余. 通过添加允许临时覆盖实体数据的规则范围, 代码变得更加难以理解和调试. 让十大靠谱网赌平台看另一个例子:

DataFactory
    .CreateBuilder()
    //另一个语法难以理解的例子
    .UseRule ( ForeignKeyRuleint>(p => p.BookId, b => b.Id))
    .UseRule ( ForeignKeyRuleint>(p => p.GroupId, g => g.GroupId))
    .UseRule ( InsideOutForeignKeyRuleint>(p => p.GroupId, ug => ug.GroupId))
    .UseRule ( ForeignKeyRuleint>(ug => ug.UserId, u => u.Id))
    .UseGroupForLastRule (singleUserGroupProvider)
    .UseRule ( ForeignKeyRuleint>(b => b.AuthorId, u => u.Id))
    .UseGroupForLastRule (singleUserGroupProvider)
    .UseRule ( DataSetterRule(u => u.用户名= “MyUser1”))
    .UseRule ( UniqueSetterRule(b => b.标题))
    .UseRule ( DataSetterRule(g => g.Name = “名称”))
    .UseDataSetterRule(p => p.许可= 1)
    //记住现有的规则集 
    .PushRuleSet ()
    //添加新的规则和创建实体 
    .UseRule ( DataSetterRule(ug => ug.水平= 1))
    .CreateSingle ()
    //回滚并再次记住 
    .PopRuleSet ()
    .PushRuleSet ()
    //对另一个数据集重复此操作 
    .UseRule ( DataSetterRule(ug => ug.水平= 2))
    .CreateSingle ().PopRuleSet ()
    .InsertAll ();

用这种线性方法,十大靠谱网赌平台很难理解什么是指什么. 额外的缩进确实有帮助,但只能在代码自动格式化之前.

因此,我做出了以下决定. 以前, we had to explicitly create a 新 builder instance for each entity 和 continue working with a linear chain of methods; now, 十大靠谱网赌平台放弃了这种方法,转而使用一组配置函数.

在此之前,一个人不能没有以下几点:

DataHelper.CreateBuilder()
    //使用规则和创作
    .InsertAll ();

目前,它只是关于调用一个单一的方法:

CreateBuilderAndInsert (
    //使用规则和创作
);

我还想简化开发人员的工作,并实现技巧, 使用语言语法对规则和逻辑进行分组. 这就是为什么我将逻辑拆分为多个接口的原因,其核心是:

  1. IScoped实体Builder 它提供了对实体创建、分组和默认规则设置方法的访问.
  2. INested实体Builder,它允许为实体定义规则

Both interfaces are 摘要 和 allow one to create rules for any type of entity; they also enable simplifying the code by providing a variation for a specific entity.

示例1. 简单的实体创建, when the rules are 集 only for one entity; adding rules for other entities, 以及创造完全不同的东西, 不工作:

var storage = BuildAndInsert(b => b
    .CreateMany (5, nb => nb
        .SetUnique(user => user.用户名、 32)
        .SetData(user => user.IsDeleted = )
    )
);

示例2. 配置多个实体:

var storage = BuildAndInsert(b => b
    //指定十大靠谱网赌平台要创建的规则和十大靠谱网赌平台想要使用的规则集 
    .CreateMany(5, nb => nb
        .SetUnique(user => user.用户名、 32)
        .SetUnique(book => book.标题)
        .UseInsideOutForeignKeyint>(user => user.Id, book => book.AuthorId)
    )
);

这个例子看起来不错,但是, 以防你有更多不同实体的规则, 这看起来可能也很奇怪, 随着数据的混合. 这意味着,必须限制数据定义区域,例如:

var storage = BuildAndInsert(b => b
    .CreateMany(5, nb => nb
        //组规则只针对用户实体 
        .For(s => s
            .SetUnique(user => user.用户名、 32)
            .SetData(user => user.IsDeleted, )
        )
        //仅对图书实体进行分组规则 
        .For(s => s
            .SetUnique(book => book.标题)
            .SetUnique(book => book.ISBN)
        )
        //链接公共生成规则流中的实体
        .UseInsideOutForeignKeyint>(user => user.Id, book => book.AuthorId)
    )
);

现在您可以看到规则已经分组, 而且编译器不允许开发人员混合使用它们. 这使得测试更容易阅读, 而如果您需要扩展代码, 您将看到在哪里添加新规则是没有问题的.

示例3. 规则可见区域.

BuildAndInsert(b => b
    //使用SetDefault,可以确定用于所有实体的一般规则 
    .SetDefault(nb => nb
        .UseForeignKeyint>(p => p.BookId, book => book.Id)
        .UseForeignKeyint>(p => p.GroupId, g => g.GroupId)
        .UseInsideOutForeignKeyint>(p => p.GroupId, gu => gu.GroupId)
        .UseForeignKeyint>(gu => gu.UserId, u => u.Id)
        .UseGroupForLastRule (singleUserGroupProvider)
        .UseForeignKeyint>(book => book.AuthorId, u => u.Id)
        .UseGroupForLastRule (singleUserGroupProvider)
        .SetData(g => g.Name = “名称”)
        .SetData(u => u.用户名= “Username1”)
        .SetUnique(book => book.标题)
    )
    //附加一个可选的创建方法参数, 可以指定仅对该操作有效的其他规则
    .CreateSingle(nb => nb
        .SetData(gu => gu.水平= 1)
    )
    .CreateSingle(nb => nb
        .SetData(gu => gu.水平= 2)
    )
);

这使得生成的代码更容易理解和, 哪个更重要, 编译器和IDE可能会给出在哪里添加规则的提示.

结论

作为一个结果, 图书馆在不断改进, 在编写复杂的SQL查询时,帮助检测最不寻常和最奇怪的错误, 用多个数据组合覆盖它们. 特别是, 当从旧的MySQL版本迁移到MariaDB时,该库帮助测试和调试意外问题. 其中一个项目, 十大靠谱网赌平台已经有大约1,000测试, 所有这些都在四分钟内完成. 由于数据库结构比较复杂,我认为这是一个相当不错的结果.

你可能也喜欢

博客文章 基于表达式树的业务规则编译器
2022年2月09年,
在这篇文章中, 我将告诉您十大靠谱网赌平台如何创建用户通知特性,以及十大靠谱网赌平台如何最终构建了一个基于表达式树的编译器,帮助十大靠谱网赌平台成功地完成了这项任务.
博客文章 例外中的例外 .净
2021年12月24日
c# /中的异常 .净可以有不同的行为. 并不是所有的,也不是所有的,都可以被处理和拦截. 本文描述了一组“击败”尝试-捕获-最终模式的异常.
博客文章 具有示例的可访问组件设计
2021年12月13日
关于ARIA属性、焦点顺序等的设计器指南. 如果您设计新的组件,这些信息将派上用场, 测试接口, 或者和前端工程师一起工作.