当你同时拥有虚拟和真实实现的接口时,单元测试的最佳方法是什么?



我熟悉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的示例,但没有建议实际应该测试什么。不过,完全有可能,我没有足够努力地搜索或没有寻找正确的东西......

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

如果真正的 UserService 实现只执行任何其他操作,只需转到数据库并按其 ID 获取用户名,则测试应测试它是否执行此操作并正确执行。如果需要,可以将其称为集成测试,但它仍然是一个应该编写和自动化的测试。

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

我建议你先读这本书:Steve Freemand 和 Nat Pryce 的《Growing Object-Oriented Software Guided by Tests》。它回答了您的问题和许多其他与TDD相关的问题。

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

JB 的答案很好,我想我会抛弃我使用过的另一种技术。

在开发原始测试时,首先不要费心去掉UserService。事实上,继续写真实的东西。按照肯特贝克的 3 条规则继续。

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

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

对于第 3 步,我们需要快速进行此测试。我们都知道,集成测试在所有事务管理和数据库设置中都很慢且容易出错。一旦我们知道代码有效,我通常不会打扰集成测试。此时,您可以引入虚拟服务,从而有效地将集成测试转换为单元测试。现在它不会以任何方式接触数据库,我们可以从列表中检查步骤 3,因为此测试现在很快。

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

希望对您有所帮助!

布兰登

最新更新