Java8:常见测试断言的静态帮助程序与默认方法

Java8:常见测试断言的静态帮助程序与默认方法,java,unit-testing,Java,Unit Testing,我已经在相当多的项目中使用Java进行了TDD,我总是要处理在某些测试之间共享一些常见断言的情况。我的前Java8解决方案总是这样 具有公共断言和静态方法的类: class CommonAssertions { static void assertCorrectUser(User user) { // bunch of assertions } } 这样使用: class FooTest { @Test void somethingToDoWithUser() {

我已经在相当多的项目中使用Java进行了TDD,我总是要处理在某些测试之间共享一些常见断言的情况。我的前Java8解决方案总是这样

具有公共断言和静态方法的类:

class CommonAssertions {
  static void assertCorrectUser(User user) {
    // bunch of assertions
  }
}
这样使用:

class FooTest {
  @Test
  void somethingToDoWithUser() {
    User user = // obtain user somehow
    CommonAssertions.assertCorrectUser(user);
  }
}
现在,在Java 8中,我尝试将接口与
default
方法一起用于常见断言:

interface CommonAssertions {
  default assertCorrectUser(User user) {
    // bunch of assertions on user
  }
}
然后,我将按照如下方式设计测试,而不是静态调用:

class FooTest implements CommonAssertions { ... }
这很相似,但第二个似乎更易于使用(节省了大量静态导入),并揭示了更多关于测试的信息。图像代码如下:

类CompanyResourceTest实现用户断言、CompanyAssertions、JsonErrorAssertions{…}


有些人可能会争辩说,
default
是为完全不同的东西设计的,这是一种误用。有些人可能会说,这和将一堆常量放入
接口中并实现它一样糟糕。但是这种方法真的有缺点吗

缺点是不清楚。接口是未指定实现细节的合同。通过使用所有默认方法,您滥用了接口的设计目的,这通常会使代码更难被其他人理解。Java是有限的,因为它不支持mixin或traits,而使用默认接口只是一种简单的方法

在java中,静态方法是这方面的标准,但如果您真的反对,我建议您使用以下几种替代方法:

  • 使用支持混合的语言编写测试,例如groovy 还是斯卡拉
  • 创建一个通用的基本测试类,比如UserTest,并让与用户相关的测试扩展它。不太理想,尤其是当您需要多重继承时
  • 编写可以在测试中注入这些方法的注释,这样就可以在这些方法中编译@UserTest

这是上的一个变体。不惜一切代价避免它。
default
方法应该是属于
接口
的东西的合理的默认实现。使用
static
实用程序方法和
import static
删除类名。如果不想冗长,只需静态导入方法即可。