让我们试试@lamektomasz提供的绝妙的解决方案。
- 创建文件
CustomParameterResolver.java
以解析@BeforeEach
和@AfterEach
注释的参数。
package com.example;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Optional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.engine.execution.BeforeEachMethodAdapter;
import org.junit.jupiter.engine.extension.ExtensionRegistry;
public class CustomParameterResolver implements BeforeEachMethodAdapter, ParameterResolver {
private ParameterResolver parameterisedTestParameterResolver = null;
@Override
public void invokeBeforeEachMethod(ExtensionContext context, ExtensionRegistry registry)
throws Throwable {
Optional<ParameterResolver> resolverOptional = registry.getExtensions(ParameterResolver.class)
.stream()
.filter(parameterResolver ->
parameterResolver.getClass().getName()
.contains("ParameterizedTestParameterResolver")
)
.findFirst();
if (!resolverOptional.isPresent()) {
throw new IllegalStateException(
"ParameterizedTestParameterResolver missed in the registry. Probably it's not a Parameterized Test");
} else {
parameterisedTestParameterResolver = resolverOptional.get();
}
}
@Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
if (isExecutedOnAfterOrBeforeMethod(parameterContext)) {
ParameterContext pContext = getMappedContext(parameterContext, extensionContext);
return parameterisedTestParameterResolver.supportsParameter(pContext, extensionContext);
}
return false;
}
@Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
return parameterisedTestParameterResolver.resolveParameter(
getMappedContext(parameterContext, extensionContext), extensionContext);
}
private MappedParameterContext getMappedContext(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return new MappedParameterContext(
parameterContext.getIndex(),
extensionContext.getRequiredTestMethod().getParameters()[parameterContext.getIndex()],
Optional.of(parameterContext.getTarget()));
}
private boolean isExecutedOnAfterOrBeforeMethod(ParameterContext parameterContext) {
return Arrays.stream(parameterContext.getDeclaringExecutable().getDeclaredAnnotations())
.anyMatch(this::isAfterEachOrBeforeEachAnnotation);
}
private boolean isAfterEachOrBeforeEachAnnotation(Annotation annotation) {
return annotation.annotationType() == BeforeEach.class
|| annotation.annotationType() == AfterEach.class;
}
}
- 创建
MappedParameterContext.java
文件
package com.example;
import java.lang.annotation.Annotation;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.platform.commons.util.AnnotationUtils;
public class MappedParameterContext implements ParameterContext {
private final int index;
private final Parameter parameter;
private final Optional<Object> target;
public MappedParameterContext(int index, Parameter parameter,
Optional<Object> target) {
this.index = index;
this.parameter = parameter;
this.target = target;
}
@Override
public boolean isAnnotated(Class<? extends Annotation> annotationType) {
return AnnotationUtils.isAnnotated(parameter, annotationType);
}
@Override
public <A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType) {
return Optional.empty();
}
@Override
public <A extends Annotation> List<A> findRepeatableAnnotations(Class<A> annotationType) {
return null;
}
@Override
public int getIndex() {
return index;
}
@Override
public Parameter getParameter() {
return parameter;
}
@Override
public Optional<Object> getTarget() {
return target;
}
}
package com.example;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@ExtendWith(CustomParameterResolver.class)
public class BaseTest {
@BeforeEach
public void beforeEach(String platformName, String platformVersion, String deviceName) {
System.out.println("Before each:");
System.out.println("platformName: " + platformName);
System.out.println("platformVersion: " + platformVersion);
System.out.println("deviceName: " + deviceName);
}
@ParameterizedTest
@CsvSource({"IOS,13.0,iPhone X Simulator", "IOS,13.2,iPhone Simulator", "IOS,13.3,iPhone XS Simulator"})
void testLogin(String platformName, String platformVersion, String deviceName) {
capabilities.setCapability("platformName", platformName);
capabilities.setCapability("platformVersion", platformVersion);
capabilities.setCapability("deviceName", deviceName);
capabilities.setCapability("methodName", testInfo.getDisplayName());
}
}
Before each:
platformName: IOS
platformVersion: 13.0
deviceName: iPhone X Simulator
===========
Before each:
platformName: IOS
platformVersion: 13.2
deviceName: iPhone Simulator
===========
Before each:
platformName: IOS
platformVersion: 13.3
deviceName: iPhone XS Simulator
===========
@ExtendWith(CustomParameterResolver.class)
,那么他“必须”使用@ParameterizedTest
。这可能看起来很明显,但是想象一下:我有一个用于测试的基类,在其中我会使用@ExtendWith(CustomParameterResolver.class)
进行扩展,只是为了将“一些”派生测试类转换为参数化测试。这是不可能的。现在我必须将所有派生类都转换为使用参数化测试。我是对的吗?有什么解决方案/调整吗?(我是Java新手) - rahman@BeforeEach
中肯定是错误的。根据 jumb0jet 的回答,只对需要参数化的测试进行适当的参数化。 - Matthew Read