我正在为一个在数据库中维护用户的PHP类编写单元测试。我现在想测试创建用户是否有效,以及删除用户是否有效。我看到有多种可能性:
我已经读过,每个测试方法应该独立于其他测试方法,这意味着第三种可能性是要走的路,但这也意味着每个方法都必须自己设置测试数据(例如,如果你想测试如果可以两次添加用户。)
你会怎么做?在这种情况下,什么是良好的单元测试风格?
答案 0 :(得分:7)
两个不同的东西=两个测试。
Test_DeleteUser()
也可能位于不同的测试夹具中,因为它具有确保用户已存在的不同Setup()
代码。
[SetUp]
public void SetUp()
{
CreateUser("Me");
Assert.IsTrue( User.Exists("Me"), "Setup failed!" );
}
[Test]
public void Test_DeleteUser()
{
DeleteUser("Me");
Assert.IsFalse( User.Exists("Me") );
}
这意味着如果Test_CreateUser()
通过且Test_DeleteUser()
没有通过 - 您知道代码中负责删除用户的部分中存在错误。
更新:刚刚考虑了Charlie对依赖问题的评论 - 我的意思是如果Creation被破坏,即使删除,两个测试都会失败。我能做的最好的事情是移动一个防护检查,以便安装程序显示在错误和失败选项卡中;区分设置失败(在一般情况下,整个测试夹具显示红色应该很容易发现设置失败。)
答案 1 :(得分:1)
如何依赖于如何利用模拟和存根来实现此目的。我会采用更细粒度的方法进行2次不同的测试。
Test A
CreateUser("testuser");
assertTrue(CheckUserInDatabase("testuser"))
Test B
LoadUserIntoDB("testuser2")
DeleteUser("testuser2")
assertFalse(CheckUserInDatabase("testuser2"))
TearDown
RemoveFromDB("testuser")
RemoveFromDB("testuser2")
CheckUserInDatabase(string user)
...//Access DAL and check item in DB
如果您使用模拟和存根,则在进行集成测试之前不需要访问DAL,因此在断言和设置数据时不需要做太多工作
答案 2 :(得分:1)
通常,你应该有两种方法,但在下列情况下,现实仍然胜过纸上文字:
您需要大量昂贵的设置代码来创建要测试的对象。这是代码气味,应该修复,但有时,你真的别无选择(想想一些聚合来自几个地方的数据的代码:你真的需要所有这些地方)。在这种情况下,我编写了大型测试(测试用例可以在许多方法上分布数千行代码)。它创建数据库,所有表,用定义的数据填充它们,逐步运行代码,验证每一步。
这应该是一种罕见的情况。如果您需要,您必须主动忽略“测试应该快”的规则。这种情况非常复杂,您希望尽可能多地检查。我有一个案例,我将7个数据库表的内容转储到文件,并比较15个SQL更新中的每一个(这使我在一次测试中比较了105个文件)加上大约一百万个可以运行的断言。
此处的目标是使测试失败,以便您立即注意到问题的根源。这就像将所有约束灌输到代码中并使它们提前失败,以便您知道要检查哪个应用程序代码行。主要缺点是这些测试用例是难以维护的。应用程序代码的每次更改都意味着您必须更新105个“预期数据”文件中的许多文件。