【问题标题】:Unit testing the DAL - please critique单元测试 DAL - 请批评
【发布时间】:2010-12-10 13:22:58
【问题描述】:

在我的简单项目中,我已经准备好对 DAL 进行单元测试了。

我基本上有一个名为 FooDataAccess 的类,它有几个非常简单的函数,让我们说其中 3 个是这样的:

int InsertFoo(string fooName)
void UpdateFoo(int fooID, string fooName)
void InsertFoosDepedency(int fooID, string someValue)

我所做的是 - 在我的单元测试项目中放入 4 个 SQL 脚本,最后一个作为嵌入式资源。

1) 创建(单元测试)数据库脚本,2) 创建对象脚本,3) 插入查找表值和 4) 删除除查找表值之外的所有值

这个想法是,任何第一次使用该项目的人都应该手动运行脚本 1-3 作为一次性设置。然后在每个单元测试启动时执行脚本 #4...(在小型应用程序中,您甚至可以在测试级别运行所有这些)

好的,到目前为止一切都很好......

所以我有我的单元测试数据库设置,作为一个空的石板。测试第一个函数 InsertFoo() 显然非常简单。我调用该函数,然后只调用 Assert(ExecuteSQL("select count(*) from foo") > 1)、Assert(ExecuteSQL("select fooName from t_foo") = expected)) 等。

我有点卡住的是那些需要依赖的地方,比如我的例子中的第三个函数,甚至是更新。

暂时放弃我的测试范围内的所有外键约束是否有意义?否则,为了对 InsertFoosDepedency(int fooID, string someValue) 函数进行单元测试,我必须先执行一些任意 sql(手动向 FOO 表插入一条记录并返回 FooID)...

或者,我应该只做后者吗?

非常感谢任何和所有反馈。

更新:它使用内联 SQL 干净地创建依赖项。我想我只是在寻找对这种用于单元测试 DAL 的方法的 cmets 和批评。再次感谢

【问题讨论】:

    标签: unit-testing data-access-layer


    【解决方案1】:

    我会说从不为了测试而乱用你的架构。如果你没有把它放回去或者你的代码放回去失败,你很快就会发现自己一团糟。

    你能用Mock Objects吗?

    如果不是,我认为您所能做的就是为每个测试设置数据库前置要求。

    您可以为每个测试考虑一个单独的类,并使用 Setup 和 Teardown 方法使数据库处于适合测试的状态。

    或者您只需在 Test 方法中进行特定于测试的设置(之后您可以使用 Teardown 清空数据库)。

    【讨论】:

    • 我已经在为我的 DAL 上的所有调用者使用模拟对象。但我仍然想对 DAL 功能本身进行单元测试。我不太害怕搞砸数据库,因为这是一个专门为单元测试创​​建的数据库。也许我应该调用 InsertFoo() 来创建我的 foo 并获取我的依赖项 ID?但这会打破它是“单元”测试的概念吗???
    • 我不确定我是否关注了你。当然必须首先插入依赖项,以便某些东西可以依赖于它们?你的意思是依赖而不是依赖?
    • 再读一遍,我听起来像是一个正确的书呆子——我只是想弄清楚。所以,回到这个问题:我认为你的测试应该反映你的预期用法,所以如果你的用户可以调用 InsertFoo() 那么你应该测试它。但是,如果他们总是必须同时调用另一个,你不应该将这两个方法都设为私有并从一个超级方法调用它们吗? (如果您将它们公开以便测试它们,您可以考虑将它们设为内部并使用 InternalsVisibleToAttribute。)
    【解决方案2】:

    这听起来和我做的很相似。我在start of each test 处销毁数据库中的所有数据,然后在测试设置阶段构建该测试所需的内容。所以对于UpdateFoo,我会拥有

    void update_existingKey_updatesValue() {
       String expected = "jeff";
    
       clearDatabase();
       // Note I would use dbUnit.
       executeSQL("insert into foo values (1, 'fred')");
    
       DAL subject = new DAL(...);
       subject.update(1, expected);  
    
       //Note I would use dbUnit.   
       String actual = executeSQL("select name from foo where id = 1"); 
       assert(expected, actual);
    }
    

    在 Java 中,我使用了一个名为 dbUnit 的工具,您的方法名称建议使用 C#,所以我将指向您 dbUnit.Net,但我从未使用过它。这提供了一种更好的(无论如何是 IMO)填充数据库和验证数据库内容的方法。

    【讨论】:

      猜你喜欢
      • 2011-09-09
      • 2015-11-07
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 2012-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多