如何测试方法计算正确的结果?

时间:2012-11-25 13:22:14

标签: java testing

这听起来比我的意思更模糊,但是当在类中测试方法时,正确的过程是什么。

e.g。客户类将设置密码的md5哈希值保存到数据库,而不是实际密码。客户类中的私有方法可以使用md5哈希进行保存。

public class Customer() {

public void setPassword(String password){
  this.password = hashPassword(password);
}

private String hashPassword(String password){
  ..do stuff..
}

.. other methods ..

}

现在这只是一个例子,我不想知道如何计算md5哈希等。这是关于测试的。这是我能想到的选择:

  • 我在测试类中创建了一个与hashPassword相同的方法,然后比较结果。
  • 我手动计算特定密码(myPassword)的结果,并将其存储为常量。在测试中将密码设置为myPassword后,我会将常量与结果进行比较。

7 个答案:

答案 0 :(得分:4)

您应该选择第二个选项,即预先计算一个值或一系列值,然后使用它们进行测试。除了增加代码重复量之外,使用相同方法的副本测试方法没有任何意义。

答案 1 :(得分:1)

这样做

  

我手动计算特定密码(myPassword)的结果,并将其存储为常量。在测试中将密码设置为myPassword后,我会将常量与结果进行比较。

通过将实现与相同的实现结果进行比较,测试实现是没有意义的。

答案 2 :(得分:1)

我不会使用相同的算法,因为您可能会在两个实现中实现相同的错误。我不会手动计算,因为这种手动计算可能是错误的。相反,我会使用一些参考输入并检查算法的输出是否与参考输出相同。见the following page

MD5 test suite:
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
d174ab98d277d9f5a5611c2c9f419d9f
MD5 ("123456789012345678901234567890123456789012345678901234567890123456
78901234567890") = 57edf4a22be3c955ac49da2e2107b67a

现在,如果您信任MD5的实现,并且只想检查是否已调用消化器,则可以注入模拟MD5消化器,并在设置密码时检查是否调用了模拟消化器。

答案 3 :(得分:1)

我肯定会采取第二种方法。您想要的最后一件事是让您的测试代码在“被测单元”中复制功能。

  1. 存储已知纯文本和散列结果的列表。
  2. 使用纯文本
  3. 添加调用setPassword的测试
  4. 添加一个方法来“检查”散列值 - 如果要添加它以进行测试,请使这个包可见
  5. 这里的奖励是您没有测试hashPassword方法。您正在验证密码是否已正确哈希。您的测试代码甚至不应该知道或关心私有方法是否存在。我会质疑你是否应该测试密码是否被哈希,因为它实际上是Customer类的实现秘密,但你可能有充分的理由进行测试。

答案 4 :(得分:0)

也有第3种选择。

您可以使用JunitAddons库,它允许您使用反射测试私有方法,但它会为您隐藏反射的复杂性。

示例:通过方法setValue()将对象obj的值设置为100:

PrivateAccessor.invoke( obj, "setValue", new Class[]{int.class}, new Object[]{
    new Integer( 100 )} );

如果对象具有基本类型,则该方法返回的值将自动包装在对象中。

答案 5 :(得分:0)

从您的选项编号2我将使用ie openssl计算并存储它,以便以后比较:)

答案 6 :(得分:0)

我假设您要测试私有方法,因为它包含一些重要的逻辑。也许最好的方法是将该方法的主体移动到某个外层?

您的代码片段就是一个很好的例子 - 计算MD5应该在Customer类之外完成 - 这不是Customer的责任。

private String hashPassword(String password) {
    this.hash = PasswordHasher.hash(password)
}

以后public(or default/protected) String PasswordHasher#hash(String)很容易被测试