6

我熟悉 TDD 的基本原则,即:

  1. 编写测试,这些会因为没有实现而失败
  2. 编写基本实现以使测试通过
  3. 重构代码

但是,我对接口和实现适合的位置有点困惑。我在业余时间创建了一个 Spring Web 应用程序,而不是大吵大闹,我想了解如何更好地测试接口/实现,以我在这里创建的这个简单的示例代码为例:

public class RunMe
{

    public static void main(String[] args)
    {
        // Using a dummy service now, but would have a real implementation later (fetch from DB etc.)
        UserService userService = new DummyUserService();
        System.out.println(userService.getUserById(1));
    }
}

interface UserService
{
    public String getUserById(Integer id);
}

class DummyUserService implements UserService
{
    @Override
    public String getUserById(Integer id)
    {
        return "James";
    }
}

我已经创建了UserService接口,最终会有一个真正的实现来查询数据库,但是为了让应用程序脱离实际,我已经替换了一个DummyUserService现在只返回一些静态数据的实现。

问题:如何实施上述测试策略?

我可以创建一个名为的测试类DummyUserServiceTest并测试当我调用getUserById()它时它会返回James,如果不是浪费时间的话,看起来很简单(?)。

随后,我还可以创建一个测试类,该类RealUserService将测试getUserById()从数据库中返回用户名。这是让我有点困惑的部分,这样做,这是否本质上没有超出单元测试的边界并变得更像是一个集成测试(在数据库上的命中)?

问题(改进了一点):当使用带有虚拟/存根和真实实现的接口时,应该对哪些部分进行单元测试,哪些部分可以安全地不测试?

昨晚我花了几个小时在谷歌上搜索这个主题,主要是找到关于什么是 TDD 的教程,或者如何使用 JUnit 的示例,但在建议实际测试什么的领域中没有任何内容。不过,完全有可能是我搜索不够努力或没有寻找正确的东西......

4

3 回答 3

4

不要测试虚拟实现:它们不会在生产中使用。测试它们没有真正的意义。

如果真正的 UserService 实现除了访问数据库并通过其 ID 获取用户名之外什么都不做,那么测试应该测试它是否这样做并正确地执行。如果您愿意,可以将其称为集成测试,但它仍然是一个应该编写和自动化的测试。

通常的策略是在测试的 @Before 注释方法中用最少的测试数据填充数据库,并让您的测试方法检查数据库中存在的 ID 是否返回相应的用户名。

于 2012-05-12T09:44:59.177 回答
3

我建议您先阅读这本书:Steve Freemand 和 Nat Pryce 的《 Growing Object-Oriented Software》,由测试指导。它回答了您和许多其他与 TDD 相关的问题。

在您的特定情况下,您应该RealUserService使用数据库适配器进行可配置,这将进行真正的数据库查询。服务本身将提供服务,而不是数据持久性。看书,很有帮助:)

于 2012-05-14T17:28:10.220 回答
0

JB 的答案是一个很好的答案,我想我会扔掉我用过的另一种技术。

在开发原始测试时,不要UserService一开始就将 stub 去掉。事实上,继续写真实的东西。继续遵循肯特贝克的 3 条规则

1)让它工作。2) 做对。3)让它快速。

您的代码将进行测试,然后验证 find by id 是否有效。正如 JB 所说,此时您的测试将被视为集成测试。一旦他们通过了,我们就成功地完成了第 1 步。现在,看看设计。这样对吗?调整任何设计气味并检查列表中的第 2 步。

对于第 3 步,我们需要快速进行此测试。我们都知道,所有事务管理和数据库设置的集成测试都很慢且容易出错。一旦我们知道代码可以工作,我通常不会为集成测试而烦恼。正是在这个时候,您可以引入您的虚拟服务,有效地将您的集成测试变成一个单元测试。现在它没有以任何方式触及数据库,我们可以从列表中删除第 3 步,因为这个测试现在很快。

那么,这种方法有什么问题呢?好吧,很多人会说我仍然需要对数据库支持的UserService. 我通常不会在我的项目中保留集成测试。我的观点是,这些类型的测试很慢、很脆弱,并且在大多数项目中没有捕捉到足够的逻辑错误来为自己买单。

希望有帮助!

布兰登

于 2012-05-14T11:36:07.187 回答