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

时间:2012-05-12 09:15:58

标签: java unit-testing interface junit tdd

我熟悉TDD的基本原则:

  1. 编写测试,由于没有实现,这些将失败
  2. 编写基本实现以使测试通过
  3. 重构代码
  4. 但是,我对接口和实现适合的位置感到困惑。我正在业余时间创建一个Spring Web应用程序,而不是用枪支开发,我想了解如何更好地测试接口/实现,采用我在这里创建的简单示例代码:< / p>

    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时,如果不浪费时间(?),这似乎很简单。< / p>

    随后,我还可以创建一个测试类RealUserService来测试getUserById()从数据库返回用户名。这个部分让我感到困惑,这样做,这实际上是不是超越了单元测试的边界,而是变成了一个整合测试(点击数据库)?

    问题(改进,一点点):当使用具有虚拟/存根的接口和实际实现时,哪些部分应该进行单元测试,哪些部分可以安全地保持未经测试?

    昨晚我花了几个小时搜索这个主题,并且大多发现了关于TDD的教程,或者如何使用JUnit的示例,但在建议实际应该测试的内容中没有任何内容。完全有可能,我没有足够的搜索或者没有找到合适的东西......

3 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:3)

我建议你先阅读本书:{4}由Steve Freemand和Nat Pryce阅读。它回答了你的问题以及与TDD相关的许多其他问题。

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

答案 2 :(得分:0)

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

在开发原始测试时,首先不要打扰UserService。事实上,继续写下真实的东西。继续Kent Beck's 3 rules

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

您的代码将进行测试,然后通过ID验证查找工作。正如JB所述,此时您的测试将被视为集成测试。一旦他们通过我们已成功完成第1步。现在,看看设计。这样对吗?调整任何设计气味并检查列表中的第2步。

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

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

希望有所帮助!

布兰登