yus*_*sif 7 java junit unit-testing parameterized maven
我正在运行这段代码,并意识到该getAllParameters()
方法由于某种原因运行了两次。由于静态字段enumMap
是在该方法之外初始化的,因此它会被填充两次,这会导致重复元素并使我正在运行的测试失败。
我认为enumMap
在方法内部初始化可以解决问题,因为当该方法第二次运行时地图确实会重置。
尽管这解决了问题,但我想知道为什么在运行 Maven Test 时会发生这种情况?我尝试了参数的数量,认为这可能会影响方法运行的次数,但它似乎只运行了两次。
@RunWith(Parameterized.class)
public class MyTest {
private static Map<String, List<Class<? extends LocalizedJsonEnum>>> enumMap = new HashMap<>();
@Parameter
@SuppressWarnings({"WeakerAccess", "unused"})
public Class<? extends LocalizedJsonEnum> currentEnum;
@Parameter(value = 1)
@SuppressWarnings({"WeakerAccess", "unused"})
public String currentClassName;
/**
* Generate a list of all the errors to run our test against.
*
* @return the list
*/
@Parameters(name = "{1}.class")
public static Collection<Object[]> getAllParameters() throws Exception {
Collection<Object[]> parameters = new LinkedList<>();
Reflections reflections = new Reflections("com.class.path");
Set<Class<? extends LocalizedJsonEnum>> JsonEnums = reflections.getSubTypesOf(LocalizedJsonEnum.class);
//workaround: initialize here
//enumMap = new HashMap<>();
//some code that inserts elements into the enumMap and parameters
return parameters;
}
@Test
public void testEnumIdentifierIsNotDuplicated() throws Exception {
String enumId;
if (currentEnum.isAnnotationPresent(Identifier.class)) {
enumId = currentEnum.getAnnotation(Identifier.class).value();
} else {
enumId = currentEnum.getSimpleName();
}
List<Class<? extends LocalizedJsonEnum>> enumList = enumMap.get(enumId);
if (enumList.size() > 1) {
StringBuilder sb = new StringBuilder("Enum or identifier [" + enumId + "] has been duplicated in the following classes:\n");
for (int listIndex = 0; listIndex < enumList.size(); listIndex++) {
Class<? extends LocalizedJsonEnum> enumDuplicate = enumList.get(listIndex);
sb.append(" [").append(listIndex).append("] Enum Class:[").append(enumDuplicate.getName()).append("]\n");
}
fail(sb.toString());
}
}
Run Code Online (Sandbox Code Playgroud)
您已经有了一个参数化的测试函数,因此,系统将运行它两次 - 每个参数一次。
关于如何做到这一点,有不同的合理方法。
一个简单的解决方案就是做最明显的事情。从测试框架来看:
MyTest
。当然,这会导致字段和调用的“重用”——第二次测试运行中的对象被“污染”。因此,这实际上并不是任何测试框架的工作原理。相反,他们这样做:
MyTest
。但是,因为你正在使用static
这个仍然不够好。每个测试调用的一个新实例不会执行任何“重置”静态内容的操作。因此,测试框架可以执行这种更加复杂的设置:
这将执行您想要的操作:每个“测试调用”(这里有 1 个测试方法和 2 个调用;每个参数选项一个)都会获得一张完全空白的石板。
然而,这将对性能产生很大影响。类加载比较昂贵;你需要在磁盘上打开一个文件,即使你依赖操作系统来缓存(因为每个测试每次都会打开 jar 文件的同一部分或诸如此类的东西),将一袋字节转换为类定义,运行验证器,这并不便宜。“运行测试套件需要很长时间”的特性是一种生产力消耗,没有人愿意为此付出代价,但是,拥有“干净的石板”测试,其中测试运行的顺序对结果没有影响也是每个人都想要的。那么我们在哪里切这个特殊的蛋糕呢?我们是否为人们提供了他们喜欢的“测试独立性”,但代价是测试套件运行缓慢?或者我们是否让他们尽可能快地进行测试运行,但像昨天的报纸一样抛弃测试独立性的概念?
真正的答案是在中间的某个地方,并带有一些可配置性。
这是我强烈建议你做的:
static
除非您有意希望在多次调用之间重用测试的某些方面,否则请避免在测试代码中使用。@Setup
应该@Teardown
用于@BeforeEach
此内容。@BeforeAll
@BeforeClass
现在您可以完全控制遇到的问题:
您可以将“创建” 的代码放在enumList
一个单独的方法中,该方法本身不是@Test
. 事实并非如此static
。
您将此方法标记为好像@BeforeAll
您希望它运行一次。@BeforeEach
如果您更喜欢较慢但更“独立”的概念,则可以标记它。当然,代码应该“重置”(它不应该只是添加内容,它应该清除/创建一个新列表并填充它)。