12

我正在使用 Code First 将类映射到现有数据库。我需要一种方法来对这些映射进行单元测试,这些映射混合了基于约定、基于属性和 fluent-api。

要进行单元测试,我需要确认类的属性映射到数据库中正确的表名和列名。此测试需要针对上下文执行,并且应首先涵盖代码的所有配置选项。

在非常高的层次上,我希望断言类似(伪代码):

Assert.IsTrue(context.TableFor<Widget>().IsNamed("tbl_Widget"));
Assert.IsTrue(context.ColumnFor<Widget>(w => w.Property).IsNamed("WidgetProperty"));
4

3 回答 3

2

另一个要考虑的想法是使用 Linq 和 ToString()。

例如:

context.Widget.Select(c => c.Property).ToString()

将导致 SQL Server Provider 出现这种情况:

"SELECT [Var_3].[WidgetProperty] AS [WidgetProperty] FROM [dbo].[Widget]..."

现在我们可以将它全部隐藏在一些扩展方法中并解析生成的 SQL,它看起来几乎就像你的伪代码:

Assert.IsTrue(context.Widgets.GetSqlColumnNameFor(w => w.Property).IsNamed("WidgetProperty"));

延期草案:

public string GetSqlColumnNameFor<TSource>(this DbSet<T> source, Expression<Func<TSource, TResult>> selector)
{
    var sql = source.Select(selector).ToString();

    var columnName = sql... // TODO : Some regex parsing

    return 
       columnName;
}

类似地,我们可以创建 GetSqlTableNameFor()。

更新:我决定寻找一些专用的 SQL 解析器,所以这个解决方案更通用,显然 .NET 有这样的事情:

http://www.dpriver.com/blog/list-of-demos-illustrate-how-to-use-general-sql-parser/generate-internal-query-parse-tree-in-xml-for-further-加工/

于 2016-06-01T06:30:58.327 回答
0

如果你写了一个方法

public static string ToMappingString(this Widget obj)

然后您可以通过批准测试(www.approvaltests.com 或 nuget)轻松地对此进行测试

这里有一个视频:http ://www.youtube.com/watch?v=vKLUycNLhgc

但是,如果您要测试“我的对象保存并自行检索”,那么这是“基于理论的测试”的理想场所

基于理论的测试 大多数单元测试采用以下形式

Given A,B expect C

基于理论的测试是

Given A,B expect Theory

这样做的好处是无需担心 A 和 B 采用哪种特定形式,因为您不需要知道 C,因此任何随机生成器都可以工作。

示例 1:测试 Add 和 Subtract 方法

通常你会有类似的东西

Assert.AreEqual(5, Add(2,3));
Assert.AreEqual(9, Add(10,-1));
Assert.AreEqual(10, Add(5,5));
Assert.AreEqual(7, Subtract(10,3));

但是,如果您编写了一个理论测试,它看起来像

for(int i = 1; i < 100; i++)
{ 
    int a = random.Next();
    int b = random.Next();
    Assert.AreEqual(a, Subtract(Add(a,b),b, string.Format("Failed for [a,b] = [{0},{1}], a,b));        
}

既然您了解了基于理论的测试,那么您要测试的理论是

Given Model A
When A is stored to the database, and retrieved the resulting object is equal to A
于 2012-05-10T14:27:39.270 回答
0

我能想到的涵盖所有可能选项的唯一方法是使用 Entity Framework Power Tools 来预编译 DbContext 的视图,并且可能结合使用对生成的类型的反射和对生成的代码本身的 RegEx验证一切都按照您想要的方式映射。对我来说听起来很痛苦。

想到的另一件事是围绕 DbModelBuilder 创建一个外观来拦截和检查通过它的所有内容,但我不知道这是否会处理基于约定的内容。听起来也很痛苦。

作为一个不太完整但更简单的替代方案,您可以通过尽可能切换到基于属性的映射来消除其中的很大一部分。这将允许您创建一个基本测试类,例如 ModelTesting<TEntity>,其中包括一些使用反射来验证 TEntity 具有的测试方法:

  • 单个 TableAttribute。
  • 每个属性都有一个 ColumnAttribute 或 NotMappedAttribute。
  • 至少一个具有 KeyAttribute 的属性。
  • 每个属性类型都映射到一个兼容的数据库类型。

您甚至可以根据属性和类的名称强制执行命名约定(需要注意每个层次结构的表类型)。也可以检查外键映射。这是一个只写一次的基类,您可以为每种模型类型派生一次,并捕获您的大部分错误(好吧,它捕获了我的大部分错误)。

任何不能用属性表示的东西,比如 TPH 继承等等,都会变得有点困难。假设您的 DbContext 没有为您生成数据库,那么启动 DbContext 并在 Set<TEntity>() 上执行 FirstOrDefault 的集成测试可能会涵盖大部分这些基础。

于 2012-04-26T04:54:48.187 回答