【问题标题】:Providing tests as part of a library作为库的一部分提供测试
【发布时间】:2016-01-16 01:12:57
【问题描述】:

假设一个接口像:

public interface Fooer {
  void foo();
  boolean isFooed();
}

这是我正在编写的 Java 库的一部分。这个库的用户应该实现这个接口并将对象传递到我的库中。

我想为用户提供一种方法来测试他们的实现以保持我的库代码假设的不变量。

按照上面的例子:

Fooer f = getUsersFooer();
f.foo();
// f.isFooed() MUST return true now

是否有可能提供此类测试作为库的一部分,如果可以,是否可行甚至可以接受?

(我不知道这些是否会被视为单元测试或集成测试......他们使用 getter 方法或非常原始的非变异方法测试由单个方法所做的修改)

当然,我可以编写类似的类

public class TestFooer {
  public static boolean test(Fooer f) {
    // ...
  }
}

但是有没有一种“标准方式”,使用通常的测试框架(JUnit,...)?

【问题讨论】:

  • 我不知道是否有标准方法,但是首先,我将创建一个具有单个抽象方法 createFoo() 的抽象类,然后是具体的测试方法,而不是静态方法。或者某种 DI —— DI 框架和测试框架之间可能存在集成。
  • 我认为没有标准的方法可以做到这一点,但恕我直言,静态方法是一种很好的方法。您不应该在您的库中使用任何 JUnit 代码并通过简​​单地抛出 AssertionsError 来进行断言。这使您的测试可以与 TestNG 和 JUnit 一起使用。
  • 这些测试是集成测试:它们测试关于其他组件的假设是否成立。相反,在单元测试中,当您创建双精度对象(模拟、存根)时,您会根据您对其他组件的假设来实现它们。也就是说,单元测试不适合识别对其他组件的误解。

标签: java unit-testing testing junit


【解决方案1】:

这是一种常见的模式,用于检查某些规范实现的合规性。这称为 TCK,Technology Compatibility Kit。很多TCK的代码我没看过,但是经常看到他们用TestNG

最近在 JUnit 5.8.0-M1 中添加了一个允许定义可用于此目的的测试套件。

您的 TCK 对您的 API 和 org.junit.jupiter:junit-jupiter(至少 5.8.0-M1)加上 org.junit.platform:junit-platform-suite(至少 1.8.0-M1)有一个非测试依赖。测试不在src/test/java,而是src/main/java。然后向 TCK 添加一个套件类,例如:

package org.example;

import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;

@Suite
@SelectPackages("org.example")
public abstract class TestCompatibilityKitSuite {}

请注意,这个类不必是抽象的,我只是认为它使预期的用途更加清晰。

然后,该实现依赖于api 和一个test 依赖于tck。要运行测试,请添加如下类:

package test;

import org.example.TestCompatibilityKitSuite;

class TckTest extends TestCompatibilityKitSuite {}

TCK 必须加载实现。一个好方法是使用java.util.ServiceLoader。有关完整示例,请查看 here

【讨论】:

  • 感谢您的回答,这看起来很有趣!是否也可以将 API、TCK 和实现放入不同的包中?我将Impl1.javaorg.example 移动到org.example.impl,但随后我得到一个java.util.ServiceConfigurationError: org.example.Api: Provider org.example.Impl1 not found at org.example.ApiTest。(ApiTest.java:9) 构建实现项目时出错。我不确定那里发生了什么:为什么它认为 Impl1 根本就在 org.example 包中?
  • @efie:是的,它们可以在不同的包中。您的问题是关于 ServiceLoader 实际上是如何工作的。 impl 的完全限定名称位于 META-INF/services 中的一个文件中,该文件具有 API 的名称。看来您应该将该文件的内容更新为 org.example.impl.Impl1
  • 非常感谢您的指点!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 1970-01-01
  • 1970-01-01
  • 2019-11-28
  • 2017-12-30
  • 2017-05-11
相关资源
最近更新 更多