如何在 JUnit 5 中参数化 beforeEach()?
How to Parameterize beforeEach() in JUnit 5?
我使用 JUnit 5 作为我的测试运行器。
在设置方法中,我硬编码了 3 个参数(platformName
、platformVersion
和 deviceName
)。我有一个应该测试各种组合的测试方法......这意味着,当 运行 宁我的 testLogin()
测试时,它应该 运行 在多个平台名称,版本,设备名称.. .
所以,我尝试如下...
@BeforeEach
@CsvSource({"IOS,13.0,iPhone X Simulator", "IOS,13.2,iPhone Simulator", "IOS,13.3,iPhone XS Simulator"})
void setUp(String platformName, String platformVersion, String deviceName) throws MalformedURLException {
....
capabilities.setCapability("platformName", platformName);
capabilities.setCapability("platformVersion", platformVersion);
capabilities.setCapability("deviceName", deviceName);
capabilities.setCapability("methodName", testInfo.getDisplayName());
}
我的问题是,beforeEach()
方法如何参数化?另外,我想获取测试方法名称...因此,如果我指定参数,那么我应该在哪里指定 TestInfo 参数。
请帮帮我。我也看到了下面的问题...
========
public class TestBase {
@BeforeEach
void setUp(TestInfo testInfo) throws MalformedURLException {
MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "13.2");
capabilities.setCapability("deviceName", "iPhone Simulator");
capabilities.setCapability("name", testInfo.getDisplayName());
capabilities.setCapability("app", “/home/my-user/testapp.zip");
driver = new IOSDriver(
new URL("https://192.168.1.4:5566/wd/hub"),
capabilities
);
}
}
public class LoginTest extends TestBase {
@Test
public void testLogin() {
driver.findElement(By.id("user-name")).sendKeys(“myuser);
driver.findElement(By.id("password")).sendKeys(“mypassword);
driver.findElement(By.id(“login_btn”)).click();
assertTrue(true);
}
}
您不能参数化 @BeforEach
方法。 JUnit5 仅支持参数化测试(测试方法)。
参数化测试与常规 @Test
方法一样声明,但使用 @ParameterizedTest
注释代替。此外,您必须声明至少一个来源(例如 @CsvSource
、@ValueSource
等)
例如:
@ParameterizedTest
@CsvSource({
"apple, 1",
"banana, 2",
"'lemon, lime', 0xF1"
})
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
让我们试试@lamektomasz 的 awesome solution。
- 创建文件
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
===========
我使用 JUnit 5 作为我的测试运行器。
在设置方法中,我硬编码了 3 个参数(platformName
、platformVersion
和 deviceName
)。我有一个应该测试各种组合的测试方法......这意味着,当 运行 宁我的 testLogin()
测试时,它应该 运行 在多个平台名称,版本,设备名称.. .
所以,我尝试如下...
@BeforeEach
@CsvSource({"IOS,13.0,iPhone X Simulator", "IOS,13.2,iPhone Simulator", "IOS,13.3,iPhone XS Simulator"})
void setUp(String platformName, String platformVersion, String deviceName) throws MalformedURLException {
....
capabilities.setCapability("platformName", platformName);
capabilities.setCapability("platformVersion", platformVersion);
capabilities.setCapability("deviceName", deviceName);
capabilities.setCapability("methodName", testInfo.getDisplayName());
}
我的问题是,beforeEach()
方法如何参数化?另外,我想获取测试方法名称...因此,如果我指定参数,那么我应该在哪里指定 TestInfo 参数。
请帮帮我。我也看到了下面的问题...
========
public class TestBase {
@BeforeEach
void setUp(TestInfo testInfo) throws MalformedURLException {
MutableCapabilities capabilities = new MutableCapabilities();
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "13.2");
capabilities.setCapability("deviceName", "iPhone Simulator");
capabilities.setCapability("name", testInfo.getDisplayName());
capabilities.setCapability("app", “/home/my-user/testapp.zip");
driver = new IOSDriver(
new URL("https://192.168.1.4:5566/wd/hub"),
capabilities
);
}
}
public class LoginTest extends TestBase {
@Test
public void testLogin() {
driver.findElement(By.id("user-name")).sendKeys(“myuser);
driver.findElement(By.id("password")).sendKeys(“mypassword);
driver.findElement(By.id(“login_btn”)).click();
assertTrue(true);
}
}
您不能参数化 @BeforEach
方法。 JUnit5 仅支持参数化测试(测试方法)。
参数化测试与常规 @Test
方法一样声明,但使用 @ParameterizedTest
注释代替。此外,您必须声明至少一个来源(例如 @CsvSource
、@ValueSource
等)
例如:
@ParameterizedTest
@CsvSource({
"apple, 1",
"banana, 2",
"'lemon, lime', 0xF1"
})
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
让我们试试@lamektomasz 的 awesome solution。
- 创建文件
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
===========