guava
我目前正在为LibFX添加一项新功能,为此我创建了一些类似于Java Collections Framework中的自定义集合的自定义集合。 我一直在寻找可以与之对抗的测试,并很高兴地发现Google的Guava包含了我所需要的:一个庞大的测试套件,它针对JDK和Guava的所有集合接口验证了我实现的每个细节。
让我们快速浏览一下。
总览
这篇文章将首先展示如何设置项目,然后再着手进行实际测试。
我没有创建专门的示例,但是您可以看到我如何在LibFX中使用它。
设定
为此,我们需要JUnit,Guava-Testlib和一些样板代码。
获取JUnit
如果您尚未在项目中使用JUnit,请在此处获取。 如果您使用Maven或Gradle:
Maven的依赖项信息
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Gradle的依赖项信息
testCompile 'junit:junit:4.12'
获取番石榴
我们实际上需要的不是Guava本身,而是Guava-Testlib 。 您可以从中央存储库下载它, 该存储库还包含不同管理者的依赖项信息。
为了您的方便:
Maven的依赖项信息
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>18.0</version>
<scope>test</scope>
</dependency>
Gradle的依赖项信息
testCompile 'com.google.guava:guava-testlib:18.0'
写一些样板
假设您要编写一个MySet
和相应的MySetTest
。
通过JUnit-3.8.x方式,创建一个方法public static Test suite();.
JUnit查找此方法,并使用它来识别将为该类运行的所有测试。 在该方法内,创建一个TestSuite并添加我们将进一步编写的测试:
MySetTest中的样板
public class MySetTest {
public static Test suite() {
return new MySetTest().allTests();
}
public Test allTests() {
TestSuite suite =
new TestSuite("package.name.of.MySetTest");
suite.addTest(testForOneToWayUseMySet());
suite.addTest(testForAnotherWayToUseMySet());
return suite;
}
}
(我没有尝试使用JUnit 4的注释来做到这一点。
放置好样板后,您可以使用JUnit运行此类,例如,从IDE内部或CI服务器上运行此类。
测试您的实施
至此,我们可以开始为实现实际创建测试了。 或者,更准确地说,告诉番石榴如何为我们做到这一点。 这是一个分为两部分的过程:一个为集合中的元素和被测单元创建一个生成器,另一个使用Guava的测试套件构建器之一来创建针对实现量身定制的全面测试集。
我们将继续测试Set
的实现。 在下面,我们将看到可用的其他接口测试套件。
元素生成器和被测单元
测试套件生成器要求您允许在集合中创建样本元素并实例化集合。 为此,您必须实现TestSetGenerator<E>
(其中E
是元素的类型)。
这很简单, order(List<E>)
是可能需要考虑的唯一方法。 请注意,与文档相反,即使未报告CollectionFeature.KNOWN_ORDER
,testlib(18.0)的当前版本也确实调用了此方法(有关功能的详细信息,请参见下文)。 就我而言,返回插入顺序就足够了。
测试套件生成器
现在,这才是真正的魔术发生。 您从上方获取生成器,将其传递给正确的测试套件生成器,指定您的集合具有哪些功能,它将创建定制的全面测试套件:
使用“ SetTestSuiteBuilder”创建测试
public Test testForOneToWayUseMySet() {
return SetTestSuiteBuilder
.using(new MySetGenerator())
.named("one way to use MySet")
.withFeatures(
CollectionSize.ANY,
CollectionFeature.ALLOWS_NULL_VALUES,
CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
CollectionFeature.SUPPORTS_ADD,
CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
CollectionFeature.SUPPORTS_REMOVE,
)
.createTestSuite();
}
特征
指定正确的功能很重要。 查看两个枚举CollectionSize
和CollectionFeatures
以查看存在哪些可能性来描述集合的行为。
请注意,创建的测试会同时验证功能! 例如,如果ALLOWS_NULL_VALUES
,构建器将生成测试,以验证向集合添加null会抛出NullPointerException
。
抑制测试
通过在构建器上调用suppressing
,您可以指定将不会运行的测试方法。 当这些功能不足以精确指定行为时,它似乎是最后的选择。 我没有使用它。
设置与拆卸
如果必须在每次测试之前或之后运行代码,则可以将其作为Runnable
分别withTearDown
给withSetUp
或withTearDown
(都可以在构建器上调用)。
可用的测试套件
当然,您也可以为其他接口生成测试套件。 乍一看就产生了以下可能性:
Java的集合:
- 采集
- 迭代器
- 清单
- 地图
- 导航地图
- 导航集
- 队列
- 组
- SortedMap
- SortedSet
番石榴的收藏:
- 双图
- ListMultimap
- 多图
- 多集
- SetMultimap
- SortedMultiset
- SortedSetMultimap
对* TestSuiteBuilder进行类型搜索(请注意通配符)会产生一些其他生成器。 我没有对其进行调查,但是有可能将其用于其他情况下的测试。
为了使用它们,只需实现相应的Test...Generator
并将其交给相应的...TestSuiteBuilder
。
反射
我们已经看到了如何使用Guava的Testlib测试集合的实现:如何将其和JUnit包含在我们的项目中,我们需要使其运行的样板文件以及生成器和测试套件生成器的概述。 后者是发生所有魔术的地方,它可以创建全面的测试,以适合我们对实现及其功能的描述。
翻译自: https://www.javacodegeeks.com/2015/03/test-collection-implementations-with-guava.html
guava