单元测试C#和NUnit中的数据库库

时间:2010-07-20 14:01:43

标签: c# unit-testing nunit

我最近开始使用NUnit和现在的Rhino Mocks。 我现在准备开始在C#项目中使用它。

该项目涉及一个我必须编写的数据库库。

我已经读过,测试应该是独立的,不要相互依赖,也不要依赖于测试执行的顺序。

假设我想检查FTP或数据库连接。 我会写类似

的东西
[Test]
public void OpenDatabaseConnection_ValidConnection_ReturnsTrue()
{
  SomeDataBase db = new SomeDataBaseLibrary(...);
  bool connectionOk = db.Open();
  Assert.IsTrue(connectionOk);
}

另一项测试可能涉及测试某些数据库功能,例如插入一行。

[Test]
public void InsertData_ValidData_NoExceptions()
{
      SomeDataBase db = new SomeDataBaseLibrary(...);
      db.Open();

      db.InsertSomeRow("valid data", ...);
}

我看到了几个问题:

1)问题是最后一次测试为了独立于第一次测试,必须再次打开数据库连接。 (这也需要第一次测试在打开之前再次关闭连接。)

2)另一件事是,如果SomeDataBaseLibrary发生变化,那么所有的测试方法也必须改变。

3)每次测试运行时都必须建立所有这些连接,测试速度将会下降。

处理此问题的常用方法是什么?

我意识到我可以使用DataBaseLibrary的模拟,但这不会测试库本身,这是我项目的第一个目标。

2 个答案:

答案 0 :(得分:1)

<强> 1 您可以在所有测试之前打开1个连接,并保持打开状态,直到所有使用该连接的测试结束。方法的某些属性与[Test]属性非常相似,它们指定何时应该调用该方法:

http://www.nunit.org/index.php?p=attributes&r=2.2.10

看看:

TestFixtureSetUpAttribute(NUnit 2.1) 此属性在TestFixture内部使用,以提供在执行夹具中的任何测试之前执行一次的单个函数集。 TestFixture只能有一个TestFixtureSetUp方法。如果定义了多个,则TestFixture将成功编译,但其测试将不会运行。

因此,在使用此属性定义的方法中,您可以打开数据库连接并使数据库对象成为测试环境的全局数据库对象。然后,每个测试都可以使用该数据库连接。请注意,即使测试使用相同的连接,您的测试仍然是独立的。

我相信这也解决了你的第三个问题。

我不太清楚如何回答你的第二个问题,因为我不知道SomeDataBaseLibrary类发生的变化程度。

答案 1 :(得分:0)

只是挑选,这些测试是集成测试,而不是单元测试。但是,现在我可以说,这无关紧要。

  1. 正如@sbenderli指出的那样,您可以使用TestFixtureSetUp来启动连接,并编写一个几乎为空的测试,它只是断言数据库连接的条件。我想你只需要放弃1个bug的理想 - &gt; 1测试失败,因为多个测试需要连接到测试数据库。如果使用您的数据访问层有任何副作用(例如缓存),请特别注意interacting tests(&lt; -link可能会被破坏)。
  2. 这很好。测试应该演示如何使用SUT(测试中的软件 - 在这种情况下是SomeDataBaseLibrary)。如果对SUT的更改需要更改其使用方式,您想知道。理想情况下,如果您更改SomeDataBaseLibrary会破坏客户端代码,它将破坏您的自动化测试。无论您是否进行自动化测试,都必须根据SUT进行更改;自动化测试是另一件需要改变的事情,但它们也会让你知道你必须做出改变。
  3. 使用TestFixtureSetUp进行处理。
  4. 您可能已经处理过的另一件事:InsertData_ValidData_NoExceptions不会自行清理,导致交互测试。我发现在自己之后进行测试清理的最简单方法是使用TransactionScope:只需在SetUp类中创建一个并在TearDown中处理它。根据我的经验,它就像魅力(兼容数据库)。

    编辑: 在TestFixtureSetup中有连接逻辑后,您仍然可以像这样测试连接:

    [Test]    
    public void Test_Connection() 
    {
      Assert.IsTrue(connectionOk);
    }
    

    这样做的一个缺点是测试的练习步骤是隐含的 - 它是设置逻辑的一部分。恕我直言,没关系。